feature_test_macros(7) - Linux 手册页

名称

feature_test_macros - 特性测试宏

概要

#include <features.h>

描述

特性测试宏允许程序员控制在编译程序时系统头文件所暴露的定义。

注意:为了使特性测试宏生效,它必须在包含任何头文件之前定义。这可以通过编译命令(cc -DMACRO=value)或者在源代码中包含任何头文件之前定义该宏来实现。

某些特性测试宏对于创建可移植应用程序非常有用,它们可以防止非标准定义的暴露。其他宏可用于暴露默认情况下不被暴露的非标准定义。下文描述的每个特性测试宏的确切效果可以通过查看 <features.h> 头文件来确定。

手册页中特性测试宏要求的说明

当函数要求定义某个特性测试宏时,手册页的“概要”(SYNOPSIS)部分通常包含以下形式的注释(本例摘自 acct(2) 手册页)
#include <unistd.h>

int acct(const char *filename);

Feature Test Macro Requirements for glibc (see
feature_test_macros(7)):
acct(): _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
|| 表示为了从 <unistd.h> 获取 acct(2) 的声明,必须在包含任何头文件之前定义以下宏定义中的任意一个
#define _BSD_SOURCE
#define _XOPEN_SOURCE        /* or any value < 500 */
或者,可以在编译命令中包含等效的定义
cc -D_BSD_SOURCE
cc -D_XOPEN_SOURCE           # Or any value < 500
请注意,如下文所述,某些特性测试宏是默认定义的,因此并不总是需要显式指定概要(SYNOPSIS)中显示的特性测试

在少数情况下,手册页使用简写来表示特性测试宏的要求(本例摘自 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。当使用例如 -std=c99-ansi 标志调用 gcc(1) 时,该宏会被隐式定义。
_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 扩展)的定义。

• (自 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 起)值为 600 或更大时,额外暴露 SUSv3 (UNIX 03;即 POSIX.1-2001 基础规范加上 XSI 扩展) 和 C99 定义。

• (自 glibc 2.10 起)值为 700 或更大时,额外暴露 SUSv4 (即 POSIX.1-2008 基础规范加上 XSI 扩展) 的定义。

_XOPEN_SOURCE_EXTENDED
如果定义了此宏,且同时定义了 _XOPEN_SOURCE,则会暴露符合 XPG4v2 (SUSv1) UNIX 扩展 (UNIX 95) 的定义。如果 _XOPEN_SOURCE 被定义为 500 或更大,此宏也会被隐式定义。
_ISOC95_SOURCE
暴露 ISO C (1990) 修订版 1 (也称为 C95) 的定义。此宏自 glibc 2.12 起被识别。C95 的主要变化是支持国际字符集。C95 的更改包含在随后的 C99 标准中(换句话说,_ISOC99_SOURCE 隐含了 _ISOC95_SOURCE)。
_ISOC99_SOURCE
暴露 ISO C (1990) 的 C99 扩展。此宏自 glibc 2.1.3 起被识别;早期的 glibc 2.1.x 版本识别一个名为 _ISOC9X_SOURCE 的等效宏(因为当时 C99 标准尚未定稿)。虽然该宏的使用已过时,但为了向后兼容,glibc 仍对其予以识别。
_ISOC11_SOURCE
暴露符合 ISO C11 标准的声明。此宏自 glibc 2.16 起被识别。
_LARGEFILE64_SOURCE
暴露由 LFS (Large File Summit) 指定作为“过渡性扩展”纳入单一 UNIX 规范的替代 API 定义。该替代 API 由一组名称以“64”结尾的新对象(即函数和类型)组成(例如 off64_t 对比 off_tlseek64() 对比 lseek() 等)。新程序不应使用此接口;而应使用 _FILE_OFFSET_BITS=64
_FILE_OFFSET_BITS
将此宏定义为 64,会自动将与文件 I/O 和文件系统操作相关的 32 位函数和数据类型引用转换为其 64 位对应项。这对于在 32 位系统上对大文件(> 2 GB)执行 I/O 操作非常有用。(定义此宏允许编写正确的程序只需重新编译即可使用大文件。)64 位系统自然允许大于 2 GB 的文件大小,在这些系统上该宏无效。
_BSD_SOURCE
定义此宏(无论赋什么值)会导致头文件暴露 BSD 衍生的定义。在标准冲突的情况下,定义此宏也会导致 BSD 定义被优先选用,除非定义了 _SVID_SOURCE_POSIX_SOURCE_POSIX_C_SOURCE_XOPEN_SOURCE_XOPEN_SOURCE_EXTENDED_GNU_SOURCE 中的一个或多个,在这种情况下 BSD 定义会被降级。
_SVID_SOURCE
定义此宏(无论赋什么值)会导致头文件暴露 System V 衍生的定义。(SVID == System V 接口定义;参见 standards(7)。)
_ATFILE_SOURCE (自 glibc 2.4 起)
定义此宏(无论赋什么值)会导致头文件暴露一系列以“at”结尾的函数声明;参见 openat(2)。自 glibc 2.10 起,如果 _POSIX_C_SOURCE 被定义为大于或等于 200809L,该宏也会被隐式定义。
_GNU_SOURCE
定义此宏(无论赋什么值)等同于定义 _BSD_SOURCE_SVID_SOURCE_ATFILE_SOURCE_LARGEFILE64_SOURCE_ISOC99_SOURCE_XOPEN_SOURCE_EXTENDED_POSIX_SOURCE_POSIX_C_SOURCE(值为 200809L,在 2.10 之前的 glibc 版本中为 200112L;在 2.5 之前为 199506L;在 2.1 之前为 199309L)以及 _XOPEN_SOURCE(值为 700,在 2.10 之前的 glibc 版本中为 600;在 2.2 之前为 500)。此外,还暴露了各种 GNU 专用扩展。当标准发生冲突时,BSD 定义会被降级。
_REENTRANT
定义此宏会暴露某些重入函数的定义。对于多线程程序,请改用 cc -pthread
_THREAD_SAFE
_REENTRANT 的同义词,旨在与其他某些实现兼容。
_FORTIFY_SOURCE (自 glibc 2.3.4 起)
定义此宏会触发一些轻量级检查,以便在使用各种字符串和内存操作函数时检测缓冲区溢出错误。并非所有缓冲区溢出都能被检测到,仅限于某些常见情况。在当前实现中,增加了对调用 memcpy(3)、mempcpy(3)、memmove(3)、memset(3)、stpcpy(3)、strcpy(3)、strncpy(3)、strcat(3)、strncat(3)、sprintf(3)、snprintf(3)、vsprintf(3)、vsnprintf(3) 和 gets(3) 的检查。如果将 _FORTIFY_SOURCE 设置为 1,且编译器优化级别为 1 (gcc -O1) 或更高,则执行那些不应改变兼容程序行为的检查。设置 _FORTIFY_SOURCE 为 2 会增加更多检查,但可能导致某些兼容程序运行失败。部分检查可在编译时执行并产生编译器警告;其他检查在运行时执行,如果检查失败则产生运行时错误。使用此宏需要编译器支持,gcc(1) 自 4.0 版本起提供支持。

默认定义、隐式定义和组合定义

如果没有显式定义特性测试宏,则默认定义以下特性测试宏:_BSD_SOURCE_SVID_SOURCE_POSIX_SOURCE_POSIX_C_SOURCE=200809L(在 2.10 之前的 glibc 版本中为 200112L;在 2.4 之前为 199506L;在 2.1 之前为 199309L)。

如果显式定义了 __STRICT_ANSI___ISOC99_SOURCE_POSIX_SOURCE_POSIX_C_SOURCE_XOPEN_SOURCE_XOPEN_SOURCE_EXTENDED_BSD_SOURCE_SVID_SOURCE 中的任意一个,则 _BSD_SOURCE_SVID_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 版本:在 2.4 之前的 glibc 版本中为 199506L;在 glibc 2.4 到 2.9 版本中为 200112L;自 glibc 2.10 起为 200809L。

可以定义多个宏;结果是累加的。

符合

POSIX.1 指定了 _POSIX_C_SOURCE_POSIX_SOURCE_XOPEN_SOURCE_XOPEN_SOURCE_EXTENDED 由 XPG4v2 (又称 SUSv1) 指定。

_FILE_OFFSET_BITS 未被任何标准指定,但在某些其他实现中使用。

_BSD_SOURCE_SVID_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 的系统上,以下 shell 会话展示了一些示例:

$ 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 _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 _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);
}

参见

libc(7), standards(7)

info libc 下的“特性测试宏”(Feature Test Macros)一节。

/usr/include/features.h

引用自

accept4(2), acos(3), acosh(3), addseverity(3), adjtime(3), aio_init(3), asin(3), asinh(3), asprintf(3), assert_perror(3), atan(3), atan2(3), atanh(3), atol(3), bsd_signal(3), canonicalize_file_name(3), cbrt(3), ceil(3), cfree(3), chdir(2), chmod(2), chown(2), chroot(2), clearenv(3), clock_getcpuclockid(3), clock_gettime(2), clock_nanosleep(2), clog10(3), clone(2), confstr(3), copysign(3), cos(3), cosh(3), cpu_set(3), crypt(3), ctermid(3), daemon(3), dirfd(3), dirname(3), dl_iterate_phdr(3), dlopen(3), dprintf(3), drand48(3), drand48_r(3), dup2(2), dysize(3), ecvt_r(3), encrypt(3), endian(3), erf(3), erfc(3), euidaccess(3), exec(3), exit(2), exp(3), exp10(3), exp2(3), expm1(3), fabs(3), faccessat(2), fallocate(2), fchmodat(2), fchownat(2), fcloseall(3), fcntl(2), fcvt(3), fdiml(3), fenv(3), ferror(3), fexecve(3), ffs(3), fgetgrent(3), fgetgrent_r(3), fgetpwent(3), fgetpwent_r(3), fgets(3), finite(3), flockfile(3), floor(3), fmal(3), fmax(3), fmemopen(3), fmin(3), fmod(3), fopen(3), fopencookie(3), frexp(3), fstatat(2), fsync(2), ftw(3), futimes(3), futimesat(2), fwide(3), fwprintf(3), gamma(3), gcvt(3), getaddrinfo(3), getaddrinfo_a(3), getcwd(2), getdate(3), getdirentries(3), getdtablesize(2), getdtablesize(3), getenv(3), getgrent(3), getgrnam(3), getgrouplist(3), gethostbyname(3), gethostname(2), getline(3), getloadavg(3), getlogin_r(3), getmntent(3), getnameinfo(3), getnetent_r(3), getnetgrent(3), getopt(3), getpagesize(2), getpass(3), getprotoent_r(3), getpt(3), getpw(3), getpwent(3), getpwnam(3), getresuid(2), getrlimit(2), getrpcent_r(3), getservbyname_r(3), getsid(2), getspnam(3), getsubopt(3), gettimeofday(2), getumask(3), getusershell(3), getutent(3), getutmp(3), grantpt(3), hsearch(3), hypot(3), ilogb(3), imaxabs(3), imaxdiv(3), inet_addr(3), infinity(3), initgroups(3), intro(2), intro(3), isgreater(3), isnan(3), isprint(3), iswblank(3), j0(3), kill(2), killpg(2), l64a(3), ldexp(3), linkat(2), localtime(3), lockf(3), log(3), log10(3), log1p(3), log2(3), logb(3), longjmp(3), lrint(3), lround(3), lseek64(3), madvise(2), makedev(3), man-pages(7), matherr(3), mbsnrtowcs(3), memchr(3), memfrob(3), memmem(3), mincore(2), mkdirat(2), mkdtemp(3), mkfifoat(3), mknod(2), mknodat(2), mkstemp(3), mktemp(3), modf(3), mq_receive(3), mq_send(3), mremap(2), nan(3), nanosleep(2), nexttowardl(3), nice(2), on_exit(3), open(2), opendir(3), perror(3), pipe(2), poll(2), popen(3), posix_fadvise(2), posix_fallocate(3), posix_memalign(3), posix_openpt(3), pow(3), pow10l(3), pread(2), printf(3), profil(3), program_invocation_name(3), psignal(3), pthread_attr_setaffinity_np(3), pthread_attr_setstack(3), pthread_getattr_np(3), pthread_setaffinity_np(3), pthread_setname_np(3), pthread_sigqueue(3), pthread_tryjoin_np(3), pthread_yield(3), ptsname(3), putenv(3), putgrent(3), putpwent(3), putw(3), qfcvt(3), qsort(3), rand(3), random_r(3), rcmd(3), readdir(3), readlink(2), readlinkat(2), realpath(3), remainder(3), remap_file_pages(2), remque(3), remquo(3), renameat(2), rexec(3), rint(3), round(3), rpmatch(3), rtld-audit(7), sbrk(2), scalb(3), scalblnl(3), scandir(3), scandirat(3), scanf(3), sched_getaffinity(2), sched_getcpu(3), seekdir(3), select(2), select_tut(2), sem_wait(3), semop(2), setbuf(3), setdomainname(2), seteuid(2), setgroups(2), sethostid(2), setjmp(3), setns(2), setpgrp(2), setresuid(2), setreuid(2), setstate(3), sigaction(2), sigaltstack(2), siginterrupt(3), signal(2), signbit(3), signgam(3), significand(3), sigpause(3), sigpending(2), sigprocmask(2), sigqueue(2), sigqueue(3), sigset(3), sigsetops(3), sigsuspend(2), sigtimedwait(2), sigvec(3), sigwait(3), sin(3), sincos(3), sinh(3), sockatmark(3), splice(2), sqrt(3), ssignal(3), stat(2), stime(2), stpncpy(3), strchr(3), strerror(3), strfry(3), strndup(3), strnlen(3), strptime(3), strsep(3), strsignal(3), strstr(3), strtod(3), strtok_r(3), strtol(3), strtoull(3), strverscmp(3), swab(3), symlink(2), symlinkat(2), sync(2), sync_file_range(2), syscall(2), syslog(3), sysv_signal(3), tan(3), tanh(3), tcflush(3), tcgetsid(3), tee(2), telldir(3), tempnam(3), tgamma(3), timegm(3), timer_create(2), timer_delete(2), timer_getoverrun(2), timer_settime(2), timeradd(3), toascii(3), trunc(3), truncate(2), tsearch(3), ttyslot(3), tzset(3), ualarm(3), unlinkat(2), unlocked_stdio(3), unlockpt(3), unsetenv(3), unshare(2), usleep(3), utimensat(2), vfork(2), vhangup(2), vmsplice(2), wait(2), wait4(2), wcpcpy(3), wcpncpy(3), wcscasecmp(3), wcsdup(3), wcsncasecmp(3), wcsnlen(3), wcsnrtombs(3), wcswidth(3), wcwidth(3), wordexp(3), writev(2), y0(3)