feature_test_macros(7) макросы тестирования свойств

ОБЗОР


#include <features.h>

ОПИСАНИЕ

Макросы тестирования свойств позволяют программисту контролировать какие определения будут доступны из системных заголовочных файлов при компиляции программы.

ЗАМЕЧАНИЕ: В целях эффективности, макрос тестирования свойств должен быть определён до включения всех заголовочных файлов. Это можно сделать или в команде компиляции (cc -DМАКРОС=значение) или определив макрос в исходном коде до включения заголовочных файлов.

Некоторые макросы тестирования свойств полезны для создания переносимых приложений; они позволяют блокировать нестандартные определения. Другие макросы можно использовать для разблокировки нестандартных определений, которые по умолчанию недоступны. Влияние каждого макроса тестирования свойств, описанного далее, можно узнать из содержимого заголовочного файла <features.h>.

Обозначение макросов тестирования свойств в справочных страницах

Когда функции требуется определение макроса тестирования свойств в ОБЗОРЕ справочной страницы, обычно, содержится упоминание в следующем виде (этот пример взят из справочной страницы acct(2)):

#include <unistd.h>

int acct(const char *filename);

Требования макроса тестирования свойств для glibc
(см. feature_test_macros(7)):

acct(): _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)

Символ || означает, что для получения объявления acct(2) из <unistd.h> нужно определить любой из следующих макросов до включения любых заголовочных файлов:

#define _BSD_SOURCE
#define _XOPEN_SOURCE        /* или любое значение < 500 */

Или же эквивалентные определения могут быть включены следующей командой компиляции:

cc -D_BSD_SOURCE
cc -D_XOPEN_SOURCE           # или любое значение < 500

Как описывается далее, некоторые макросы тестирования свойств определяются по умолчанию, поэтому макрос не всегда нужно указывать явно даже, если он приведён в ОБЗОРЕ.

В некоторых случаях в справочных страницах используется сокращённая запись требований макросов тестирования свойств (пример из readahead(2)):


#define _GNU_SOURCE
#include <fcntl.h>

ssize_t readahead(int fd, off64_t *offset, size_t count);

Такой формат употребляется в случаях, когда достаточно одного макроса для получения объявления функции, и этот макрос не определён по умолчанию.

Макросы тестирования свойств, распознаваемые glibc

В следующих параграфах описаны макросы тестирования свойств, управляющие Linux glibc 2.x, где x > 0.

В Linux glibc распознаются следующие макросы тестирования свойств:

__STRICT_ANSI__
Стандарт ISO C. Этот макрос неявно определяется компилятором gcc(1), если он вызывается с флагом -std=c99 или -ansi.
_POSIX_C_SOURCE
При определении этого макроса из заголовочных файлов становится доступно следующее:
  • При значении 1 доступны определения, удовлетворяющие POSIX.1-1990 и ISO C (1990).
  • При значении 2 и более дополнительно доступны определения, удовлетворяющие POSIX.2-1992.
  • При значении 199309L и более дополнительно доступны определения, удовлетворяющие POSIX.1b (расширения для реального времени).
  • При значении 199506L и более дополнительно доступны определения, удовлетворяющие POSIX.1c (нити).
  • (начиная с glibc 2.3.3) При значении 200112L и более доступны определения, удовлетворяющие базовой спецификации POSIX.1-2001 (за исключением расширения XSI), а также свойства C95 (начиная с glibc 2.12) и C99 (начиная с glibc 2.10).
  • (начиная с glibc 2.10) При значении 200809L и более доступны определения, удовлетворяющие базовой спецификации POSIX.1-2008 (за исключением расширения XSI).
_POSIX_SOURCE
Определение этого устаревшего макроса с любым значением эквивалентно определению _POSIX_C_SOURCE со значением 1.
_XOPEN_SOURCE
При определении этого макроса из заголовочных файлов становится доступно следующее:
  • Определение с любым значением делает доступным определения, удовлетворяющие POSIX.1, POSIX.2 и XPG4.
  • При значении 500 и более дополнительно доступны определения, удовлетворяющие SUSv2 (UNIX 98).
  • (начиная с glibc 2.2) При значении 600L и более дополнительно доступны определения, удовлетворяющие SUSv3 (UNIX 03; т. е., базовой спецификации POSIX.1-2001 плюс расширение XSI), и определения C99.
  • (начиная с glibc 2.10) При значении 700 и более дополнительно доступны определения, удовлетворяющие SUSv4 (т. е., базовой спецификации POSIX.1-2008 плюс расширение XSI).
If __STRICT_ANSI__ не определено или определено _XOPEN_SOURCE со значением больше или равно 500 и явно не определено _POSIX_SOURCE или _POSIX_C_SOURCE, то неявно определяются следующие макросы:
_POSIX_SOURCE определяется со значением 1.
_POSIX_C_SOURCE определяется согласно значению _XOPEN_SOURCE:
_XOPEN_SOURCE < 500
_POSIX_C_SOURCE определяется со значением 2.
500 <= _XOPEN_SOURCE < 600
_POSIX_C_SOURCE определяется со значением 199506L.
600 <= _XOPEN_SOURCE < 700
_POSIX_C_SOURCE определяется со значением 200112L.
700 <= _XOPEN_SOURCE (начиная с glibc 2.10)
_POSIX_C_SOURCE определяется со значением 200809L.
_XOPEN_SOURCE_EXTENDED
Если этот макрос определён вместе с _XOPEN_SOURCE, то доступны определения, соответствующие расширениям UNIX (UNIX 95) XPG4v2 (SUSv1). Данный макрос также неявно определён, если определён _XOPEN_SOURCE со значением 500 и более.
_ISOC99_SOURCE (начиная с glibc 2.1.3)
Делает доступными объявления, удовлетворяющие требованиям стандарта ISO C99.

Ранние версии glibc 2.1.x распознавали макрос-эквивалент _ISOC9X_SOURCE (так как стандарт C99 ещё не был утверждён). Хотя использование последнего макроса не рекомендуется, glibc пока поддерживает его для обратной совместимости.

Делает доступными определения стандарта ISO C (1990) Amendment 1 («C95»). Основным изменением в C95 была поддержка международных наборов символов.

_ISOC11_SOURCE (начиная с glibc 2.16)
Делает доступными объявления, удовлетворяющие требованиям стандарта ISO C11. Определение этого макроса также включает свойства C99 и C95 (подобно _ISOC99_SOURCE).
_LARGEFILE64_SOURCE
Делает доступными объявления альтернативного программного интерфейса, определяемого в LFS (Large File Summit) как «переходного расширение» на Single UNIX Specification (смотрите программный интерфейс состоит из набора новых объектов (т. е., функций и типов), чьи имена оканчиваются на «»64 (например, off64_t и off_t, lseek64() и lseek(), и т. д.). В новых программах не нужно указывать этот макрос; вместо него указывайте _FILE_OFFSET_BITS=64.
_LARGEFILE_SOURCE
Данный макрос исторически используется для предоставления определённых функций (в частности, fseeko(3) и ftello(3)), которые обходят адресные ограничения раннего программного интерфейса (fseek(3) и ftell(3)), в котором для файловых смещений использовался long int. Данный макрос неявно определяется, если определён _XOPEN_SOURCE со значением больше или равным 500. В новых программах не нужно определять данный макрос; определение _XOPEN_SOURCE или _FILE_OFFSET_BITS со значением 64 является более предпочтительным механизмом для достижения того же результата.
_FILE_OFFSET_BITS
При определении данного макроса со значением 64 ссылки на 32-битные функции и типы данных, относящиеся к файловому вводу-выводу и операциям с файловой системой, автоматически преобразуются в их 64-битные прототипы. Это полезно для выполнения ввода-вывода в огромные файлы (> 2 гигабайт) на 32-битных системах (определение данного макроса позволяет корректно написанным программам использовать огромные файлы, для чего требуется только перекомпиляция).

64-битные системы сразу позволяют работать с файлами размером больше 2 гигабайт, и на этих системах данный макрос ничего не делает.

_BSD_SOURCE (устарел начиная с glibc 2.20)
Определение данного макроса с любым значением приводит к доступности из заголовочных файлов определений BSD.

В glibc до версии 2.18 включительно при определении данного макроса также отдаётся приоритет определениям BSD в ситуациях, когда имеется конфликт со стандартами. Если определён один из макросов _SVID_SOURCE, _POSIX_SOURCE, _POSIX_C_SOURCE, _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED или _GNU_SOURCE, то определения BSD не используются. Начиная с glibc 2.19 при наличии макроса _BSD_SOURCE определения BSD в случае конфликта приоритета не имеют.

Начиная с glibc 2.20 этот макрос считается устаревшим. Теперь он действует также как определение _DEFAULT_SOURCE, но при компиляции генерируется предупреждение (если также не определён _DEFAULT_SOURCE). Используйте _DEFAULT_SOURCE вместо него. Чтобы для кода, которому требуется _BSD_SOURCE в glibc 2.19 и старее и _DEFAULT_SOURCE в glibc 2.20 и новее, не выдавалось предупреждение при компиляции определите _BSD_SOURCE и _DEFAULT_SOURCE одновременно.

_SVID_SOURCE (устарел начиная с glibc 2.20)
При определении этого макроса с любым значением из заголовочных файлов становятся доступны определения System V (SVID == System V Interface Definition; смотрите standards(7)).

Начиная с glibc 2.20 этот макрос устарел также как _BSD_SOURCE.

_DEFAULT_SOURCE (начиная с glibc 2.19)
Данный макрос можно определить, чтобы точно знать, что будут доступны определения «по умолчанию» даже, если умолчательные макросы отключены, что случается, когда отдельные макросы определяются явно, или компилятор вызывается в одном из своих «стандартных» режимов (например, cc -std=c99). Определение _DEFAULT_SOURCE без определения отдельных макросов или вызов компилятора в одном из его «стандартных» режимов не работают.

Определения «по умолчанию» охватывают все, которые требуются POSIX.1-2008, а также различные определения из BSD и System V. В glibc 2.19 и старее эти значения по умолчанию приблизительно эквивалентны явному определению следующего:


    cc -D_BSD_SOURCE -D_SVID_SOURCE -D_POSIX_C_SOURCE=200809

_ATFILE_SOURCE (начиная с glibc 2.4)
При определении этого макроса с любым значением из заголовочных файлов становятся доступны объявления набора функций с суффиксом «at»; смотрите openat(2). Начиная с glibc 2.10 данный макрос также неявно определяется, если определён _POSIX_C_SOURCE со значением 200809L или больше.
_GNU_SOURCE
При определении этого макроса (с любым значением) неявно определяются _ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE, _XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE со значением 200809L (200112L в версиях glibc до 2.10; 199506L в версиях glibc до 2.5; 199309L в версиях glibc до 2.1) и _XOPEN_SOURCE со значением 700 (600 в версиях glibc до 2.10; 500 в версиях glibc до 2.2). Также становятся доступны различные расширения GNU.

Начиная с glibc 2.19 определение _GNU_SOURCE также неявно определяет _DEFAULT_SOURCE. В glibc до 2.20 версии определение _GNU_SOURCE также неявно определяет _BSD_SOURCE и _SVID_SOURCE.

_REENTRANT
При определении этого макроса становятся доступны определённые реентерабельные функции. Для многонитивых программ вместо него используйте cc -pthread.
_THREAD_SAFE
Синоним _REENTRANT, предоставляется для совместимости с некоторыми другими реализациями.
_FORTIFY_SOURCE (начиная с glibc 2.3.4)
Определение этого макроса вызывает выполнение нескольких простых проверок для обнаружения ошибок переполнения буфера, которые возникают в различных функциях работы со строками и памятью (например, memcpy(3), memset(3), stpcpy(3), strcpy(3), strncpy(3), strcat(3), strncat(3), sprintf(3), snprintf(3), vsprintf(3), vsnprintf(3), gets(3) и их варианты для работы с широкими символами). Для некоторых функций проверяется целостность аргумента; например, проверяется, что open(2) передали в аргументе mode, если указан флаг O_CREAT. Обнаруживаются не все проблемы, только самые распространённые.

Если значение _FORTIFY_SOURCE равно 1 и уровень оптимизации компиляции равен 1 (gcc -O1) и больше, то выполняются проверки, которые не изменяют поведение выверяемых программ. Если значение _FORTIFY_SOURCE равно 2, то добавляются дополнительные проверки, но некоторые выверяемые программы могут завершаться с ошибкой.

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

Для работы этого макроса требуется поддержка в компиляторе, доступная в gcc(1) начиная с версии 4.0.

Определения по умолчанию, неявные определения и объединяющие определения

Если макросы тестирования свойств не указаны явно, то по умолчанию действуют следующие макросы тестирования свойств: _BSD_SOURCE (в glibc 2.19 и старее), _SVID_SOURCE (в glibc 2.19 и старее), _DEFAULT_SOURCE (начиная с glibc 2.19), _POSIX_SOURCE и _POSIX_C_SOURCE=200809L (200112L в версиях glibc до 2.10; 199506L в версиях glibc до 2.4; 199309L в версиях glibc до 2.1).

Если любой из макросов __STRICT_ANSI__, _ISOC99_SOURCE, _POSIX_SOURCE, _POSIX_C_SOURCE, _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED, _BSD_SOURCE (в glibc 2.19 и старее) или _SVID_SOURCE (в glibc 2.19 и старее) указан явно, то по умолчанию не определяются макросы _BSD_SOURCE, _SVID_SOURCE и _DEFAULT_SOURCE.

Если макросы _POSIX_SOURCE и _POSIX_C_SOURCE не указаны явно и не определён __STRICT_ANSI__ или _XOPEN_SOURCE определён со значением 500 или более, то

*
_POSIX_SOURCE определяется со значением 1; и
*
_POSIX_C_SOURCE определяется с одним из следующих значений:
  • 2, если _XOPEN_SOURCE определён со значением меньше 500;
  • 199506L, если _XOPEN_SOURCE определён со значением 500 или более, но меньше 600; или
  • (начиная с glibc 2.4) 200112L, если _XOPEN_SOURCE определён со значением 600 или более, но меньше 700.
  • (начиная с glibc 2.10) 200809L, если _XOPEN_SOURCE определён со значением 700 или более.
  • Старые версии glibc не знают о значениях 200112L и 200809L у _POSIX_C_SOURCE, и значение этого макроса зависит от версии glibc.
  • Если макрос _XOPEN_SOURCE не определён, то значение _POSIX_C_SOURCE зависит от версии glibc: 199506L в версиях glibc до 2.4; 200112L в glibc от 2.4 до 2.9 и 200809L в glibc 2.10 и новее.

Можно определять несколько макросов; результат складывается.

СООТВЕТСТВИЕ СТАНДАРТАМ

В POSIX.1 описаны _POSIX_C_SOURCE, _POSIX_SOURCE и _XOPEN_SOURCE. Макрос _XOPEN_SOURCE_EXTENDED указан в XPG4v2 (также называемом SUSv1).

Макрос _FILE_OFFSET_BITS отсутствует в стандартах, но используется в некоторых других реализациях.

Макросы _BSD_SOURCE, _SVID_SOURCE, _DEFAULT_SOURCE, _ATFILE_SOURCE, _GNU_SOURCE, _FORTIFY_SOURCE, _REENTRANT и _THREAD_SAFE есть только в Linux (glibc).

ЗАМЕЧАНИЯ

Файл <features.h> есть только в Linux/glibc. В других системах есть аналогичный файл, но, обычно, с другим именем. Данный заголовочный файл, если нужен, автоматически включается из других заголовочных файлов: его необязательно явно указывать для использования макросов тестирования свойств.

Согласно указанным макросам тестирования свойств раньше файла <features.h>, внутри него определяются другие различные макросы, которые проверяются в других заголовочных файлах glibc. Эти макросы имеют имена, начинающиеся с двух подчёркиваний (например, __USE_MISC). Программы никогда не должны определять эти макросы самостоятельно: вместо этого нужно задействовать соответствующий макрос тестирования свойств из перечисленных ранее.

ПРИМЕР

Представленную далее программу можно использовать для изучения какие значения присваиваются макросам тестирования свойств в зависимости от версии glibc и какие макросы тестирования свойств устанавливаются явно. В следующем сеансе оболочки на системе с glibc 2.10 показаны несколько примеров того, что мы увидели:
$ cc ftm.c
$ ./a.out
_POSIX_SOURCE defined
_POSIX_C_SOURCE defined: 200809L
_BSD_SOURCE defined
_SVID_SOURCE defined
_ATFILE_SOURCE defined
$ cc -D_XOPEN_SOURCE=500 ftm.c
$ ./a.out
_POSIX_SOURCE defined
_POSIX_C_SOURCE defined: 199506L
_XOPEN_SOURCE defined: 500
$ cc -D_GNU_SOURCE ftm.c
$ ./a.out
_POSIX_SOURCE defined
_POSIX_C_SOURCE defined: 200809L
_ISOC99_SOURCE defined
_XOPEN_SOURCE defined: 700
_XOPEN_SOURCE_EXTENDED defined
_LARGEFILE64_SOURCE defined
_BSD_SOURCE defined
_SVID_SOURCE defined
_ATFILE_SOURCE defined
_GNU_SOURCE defined

Исходный код программы

/* ftm.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
#ifdef _POSIX_SOURCE
    printf("_POSIX_SOURCE defined\n");
#endif
#ifdef _POSIX_C_SOURCE
    printf("_POSIX_C_SOURCE defined: %ldL\n", (long) _POSIX_C_SOURCE);
#endif
#ifdef _ISOC99_SOURCE
    printf("_ISOC99_SOURCE defined\n");
#endif
#ifdef _ISOC11_SOURCE
    printf("_ISOC11_SOURCE defined\n");
#endif
#ifdef _XOPEN_SOURCE
    printf("_XOPEN_SOURCE defined: %d\n", _XOPEN_SOURCE);
#endif
#ifdef _XOPEN_SOURCE_EXTENDED
    printf("_XOPEN_SOURCE_EXTENDED defined\n");
#endif
#ifdef _LARGEFILE64_SOURCE
    printf("_LARGEFILE64_SOURCE defined\n");
#endif
#ifdef _FILE_OFFSET_BITS
    printf("_FILE_OFFSET_BITS defined: %d\n", _FILE_OFFSET_BITS);
#endif
#ifdef _BSD_SOURCE
    printf("_BSD_SOURCE defined\n");
#endif
#ifdef _SVID_SOURCE
    printf("_SVID_SOURCE defined\n");
#endif
#ifdef _DEFAULT_SOURCE
    printf("_DEFAULT_SOURCE defined\n");
#endif
#ifdef _ATFILE_SOURCE
    printf("_ATFILE_SOURCE defined\n");
#endif
#ifdef _GNU_SOURCE
    printf("_GNU_SOURCE defined\n");
#endif
#ifdef _REENTRANT
    printf("_REENTRANT defined\n");
#endif
#ifdef _THREAD_SAFE
    printf("_THREAD_SAFE defined\n");
#endif
#ifdef _FORTIFY_SOURCE
    printf("_FORTIFY_SOURCE defined\n");
#endif
    exit(EXIT_SUCCESS);
}