Выбрать главу

if (arg == NULL || *arg == '\0')

gnFail(fname, "null or empty string", arg, name);

base = (flags & GN_ANY_BASE)? 0: (flags & GN_BASE_8)? 8:

(flags & GN_BASE_16)? 16: 10;

errno = 0;

res = strtol(arg, &endptr, base);

if (errno!= 0)

gnFail(fname, "strtol() failed", arg, name);

if (*endptr!= '\0')

gnFail(fname, "nonnumeric characters", arg, name);

if ((flags & GN_NONNEG) && res < 0)

gnFail(fname, "negative value not allowed", arg, name);

if ((flags & GN_GT_0) && res <= 0)

gnFail(fname, "value must be > 0", arg, name);

return res;

}

long

getLong(const char *arg, int flags, const char *name)

{

return getNum("getLong", arg, flags, name);

}

int

getInt(const char *arg, int flags, const char *name)

{

long res;

res = getNum("getInt", arg, flags, name);

if (res > INT_MAX || res < INT_MIN)

gnFail("getInt", "integer out of range", arg, name);

return (int) res;

}

lib/get_num.c

3.6. Вопросы переносимости

В этом разделе мы рассмотрим, как создавать портируемые системные программы. В нем будут представлены макросы проверки возможностей и стандартные типы данных системы, определенные спецификацией SUSv3, а затем рассмотрены некоторые другие вопросы портируемости.

3.6.1. Макросы проверки возможностей

Поведение API системных вызовов и вызовов библиотечных функций регулируется различными стандартами (см. раздел 1.3). Одни стандарты определены организациями стандартизации, такими как Open Group (Single UNIX Specification), а другие — двумя исторически важными реализациями UNIX: BSD и System V, выпуск 4 (и объединенным System V Interface Definition).

Иногда при создании портируемого приложения могут понадобиться различные заголовочные файлы для предоставления только тех значений (констант, прототипов функций и т. д.), которые отвечают конкретному стандарту. Для этого определены несколько макросов проверки возможностей, которые доступны при компиляции программы.

Как один из вариантов, можно задать макрос в исходном коде программы до включения каких-либо заголовочных файлов:

#define _BSD_SOURCE 1

В качестве альтернативы можно воспользоваться ключом — D компилятора языка C:

$ cc — D_BSD_SOURCE prog.c

Название «макрос проверки возможностей» может показаться странным, но, если взглянуть на него с точки зрения реализации, можно найти вполне определенный смысл. В реализации решается, какие свойства, доступные в каждом заголовке, нужно сделать видимыми путем проверки (с помощью #if), какие значения приложение определило для этих макросов.

Соответствующими стандартами установлены следующие макросы проверки возможностей (то есть их можно портировать на все системы, поддерживающие эти стандарты).

• _POSIX_SOURCE — если он задан (с любым значением), то предоставляет определения, соответствующие POSIX.1-1990 и ISO C (1990). Этот макрос заменен макросом _POSIX_C_SOURCE.

• _POSIX_C_SOURCE — если он определен со значением 1, то он производит такой же эффект, что и макрос _POSIX_SOURCE. Если он задан со значением большим или равным 199309, то также предоставляет определения для POSIX.1b (работа с системами реального времени). Если он приведен со значением, большим или равным 199506, то он также предоставляет определения для POSIX.1c (работа с потоками). Если он задан со значением 200112, то также предоставляет определения для базовой спецификации POSIX.1-2001 (то есть с включением XSI-расширения). (До выхода версии 2.3.3 заголовки glibc не интерпретировали значение 200112 для _POSIX_C_SOURCE.) Если макрос приведен со значением 200809, то он также предоставляет определения для базовой спецификации POSIX.1-2008. (До выхода версии 2.10 заголовочные файлы glibc не интерпретировали значение 200809 для _POSIX_C_SOURCE.)

• _XOPEN_SOURCE — если он задан (с любым значением), то предоставляет определения, соответствующие POSIX.1, POSIX.2 и X/Open (XPG4). Если он приведен со значением 500 или выше, то также предоставляет определения расширений SUSv2 (UNIX 98 и XPG5). Присвоение значения 600 или выше дополнительно приводит к предоставлению определения расширений SUSv3 XSI (UNIX 03) и расширений C99. (До выхода версии 2.2 заголовки glibc не интерпретировали значение 600 для _XOPEN_SOURCE.) Задание значения 700 или выше также приводит к предоставлению определения расширений SUSv4 XSI. (До выхода версии 2.10 заголовки glibc не интерпретировали значение 700 для _XOPEN_SOURCE.) Значения 500, 600 и 700 для _XOPEN_SOURCE были выбраны потому, что SUSv2, SUSv3 и SUSv4 являются соответственно выпусками Issues 5, 6 и 7 спецификаций X/Open.

Для glibc предназначены следующие макросы проверки возможностей.

• _BSD_SOURCE — если он задан (с любым значением), то предоставляет определения, соответствующие BSD. Явная установка одного лишь этого макроса приводит к тому, что в случае редких конфликтов стандартов предпочтение отдается определениям, соответствующим BSD.

• _SVID_SOURCE — если макрос приведен (с любым значением), то он предоставляет определения System V Interface Definition (SVID).