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_t,lseek64() 对比 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); }
参见
info libc 下的“特性测试宏”(Feature Test Macros)一节。