名称
feature_test_macros - 功能测试宏
概要
#include
说明
功能测试宏允许程序员编译程序时控制由系统头文件暴露的定义。
注意:要想有效控制,必须在包含任何头文件之前定义功能测试宏。这可以在编译
命令(cc -DMACRO=value)中完成,也可以通过在源代码中定义宏来完成,这些宏
在包含头文件之前被定义。
某些功能测试宏通过避免暴露非标准定义来创建可移植应用程序,其他宏可用于暴
露默认情况下不暴露的非标准定义。
通过检查
手册页中功能测试宏要求的规范
当函数要求定义功能测试宏时,手册页的概要通常包含以下形式的注释(此示例来
自acct(2) 手册页):
#include
int acct(const char *filename);
对于glibc来说要有功能测试宏才能使用(参考feature_test_macros):
acct(): _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
“||”意味着为了从
以下宏之一:
#define _BSD_SOURCE
#define _XOPEN_SOURCE /* 或者以任何小于500的值定义该宏 */
或者,可以在编译命令中包含等效定义:
cc -D_BSD_SOURCE
cc -D_XOPEN_SOURCE # 或者以任何小于500的值定义该宏
请注意,如下文所述,某些功能测试宏是默认定义的,因此可能并不总是需要显式
定义概要中显示的功能测试宏。
在一些情况下,手册页使用简写来表达对功能测试宏的要求(这个例子来自
readahead(2)):
#define _GNU_SOURCE
#include
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隐式定义。
_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
用任何值定义这个过时的宏等同于用值1定义_POSIX_C_SOURCE。
_XOPEN_SOURCE
定义这个宏会导致头文件暴露如下定义:
·使用任何值进行定义则暴露符合POSIX.1、POSIX.2和XPG4的定义。
·该宏定义为500或更大的值则在以上基础之上还暴露了符合SUSv2(UNIX
98)的定义。
·(自glibc 2.2起)该宏定义为600或更大的值则在以上基础之上还暴露
了符合SUSv3(UNIX 03,即POSIX.1-2001基本规范加上XSI扩展)的定
义。
·(自glibc 2.10起)该宏定义为700或更大的值则在以上基础之上还暴
露了符合SUSv4(即POSIX.1-2008基本规范加上XSI扩展)的定义。
如果__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,则暴露对应于XPG4v2
(SUSv1)UNIX扩展(UNIX 95)的定义。如果_XOPEN_SOURCE定义为500
或更大值,则此宏也被隐式定义。
_ISOC99_SOURCE(自glibc 2.1.3起)
暴露符合ISO C99标准的声明。
较早的glibc 2.1.x版本识别一个名为_ISOC9X_SOURCE的等效宏(因为当时
C99标准尚未最终确定)。尽管此宏的使用已过时,但glibc继续识别它
以实现向后兼容性。
定义_ISOC99_SOURCE也会暴露ISO C(1990)修正案 1("C95")的定义。
(C95的主要变化是对国际字符集的支持。)
_ISOC11_SOURCE(自glibc 2.16起)
暴露符合ISO C11标准的声明。定义此宏也会启用C99和C95功能集(如
_ISOC99_SOURCE)。
_LARGEFILE64_SOURCE
暴露LFS(大文件峰会)指定的替代API的定义,作为单一UNIX规范的“过
渡性扩展”。(参考http://opengroup.org/platform/lfs.html。)替代API
由一组名称后缀为“64”的新对象(即函数和类型)组成(例如,off64_t
与off_t、lseek64()与lseek()等)。新程序不应使用此宏而应该使用
_FILE_OFFSET_BITS=64。
_LARGEFILE_SOURCE
该宏历史上用于暴露某些函数(特别是fseeko和ftello),这些函数解决
了早期API(特别是fseek和ftell)使用long int进行文件偏移的限制。如
果_XOPEN_SOURCE定义为大于或等于500的值,则该宏是隐式定义的。
新程序不应使用此宏。像刚才描述的那样定义_XOPEN_SOURCE或定义
_FILE_OFFSET_BITS为64是实现相同结果的首选机制。
_FILE_OFFSET_BITS
该宏定义为64会自动将文件I/O和文件系统操作相关的32位函数和数据
类型的引用转换为其64位对应项的引用。这对于在32位系统上对大文件
(> 2 GB)执行 I/O 很有用。(定义这个宏允许正确编写的程序只需要重
新编译就可以使用大文件。)
64位系统自然允许文件大小超过2 GB,并且在这些系统上此宏无效。
_BSD_SOURCE (自glibc 2.20起被弃用)
该宏定义为任何值都会导致头文件暴露BSD派生的定义。
在2.18之前包括2.18的glibc版本中,定义此宏会导致在某些标准冲突的
情况下首选BSD定义。除非定义了_SVID_SOURCE、_POSIX_SOURCE、
_POSIX_C_SOURCE、_XOPEN_SOURCE、_XOPEN_SOURCE_EXTENDED或
_GNU_SOURCE中的一个或多个,在这些情况下不推荐定义_BSD_SOURCE。
自glibc 2.20起,该宏被弃用。它现在与定义_DEFAULT_SOURCE具有相同
的效果,但会生成编译时警告(除非还定义了_DEFAULT_SOURCE)。请改
用_DEFAULT_SOURCE。要想在glibc 2.19及更早版本中使用_BSD_SOURCE
以及在glibc 2.20及更高版本中使用_DEFAULT_SOURCE的代码在编译时没
有警告,请同时定义_BSD_SOURCE和_DEFAULT_SOURCE。
_SVID_SOURCE(自glibc 2.20起被弃用)
该宏定义为任何值都会导致头文件暴露System V派生的定义。(SVID
==System V接口定义;参考standards。)
自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。从glibc 2.10开始,如果_POSIX_C_SOURCE定义为大于或等
于200809L的值,则此宏也被隐式定义。
_GNU_SOURCE
该宏定义(任意值)也隐式地定义了_ATFILE_SOURCE,
_LARGEFILE64_SOURCE,_ISOC99_SOURCE,_XOPEN_SOURCE_EXTENDED,
_POSIX_SOURCE,_POSIX_C_SOURCE定义为200809L(在glibc 2.10之前的
版本为200112L,在glibc 2.5之前的版本为199506L,在glibc 2.1之前的
版本为199309L)和_XOPEN_SOURCE定义为700(在glibc 2.10之前的版
本为600,在glibc 2.2之前的版本中为500)。此外,还暴露了各种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、memset、
stpcpy、strcpy、strncpy、strcat、strncat、sprintf、snprintf、vsprintf、vsnprintf、
gets及它们的宽字符变体)时引入一些轻量级的检查,用于侦测一些内存
溢出错误。对于某些函数会检查参数的一致性,例如,当参数flags包含
O_CREAT时,会检查open是否已提供参数mode。并非所有的问题都会
检查,只会检查一些常见情况。
如果_FORTIFY_SOURCE定义为 1,编译器的优化级别为1(gcc -O1)及以
上值,则执行不应更改符合程序行为的检查。当_FORTIFY_SOURCE定义为
2时,会添加更多的检查,但某些符合要求的程序可能会失败。
需要编译器支持才能使用该宏,自gcc 4.0起可用。
默认定义、隐式定义和组合定义
如果没有显示定义功能测试宏,则会默认定义下列功能测试宏:_BSD_SOURCE(glib
2.19和更正的版本),_SVID_SOURCE(glib 2.19和更正的版本),_DEFAULT_SOURCE
(自glib 2.19起),_POSIX_SOURCE,_POSIX_C_SOURCE=200809L(glibc 2.10之前
的版本为200112L,glibc 2.4之前的版本为199506L,glibc 2.1之前的版本为
199309L)。
如果显式定义了__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的版
本:在glibc 2.4之前的版本中为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,_DEFAULT_SOURCE,_ATFILE_SOURCE,
_GNU_SOURCE,_FORTIFY_SOURCE,_REENTRANT和_THREAD_SAFE 由Linux(glibc)
指定。
注意
不同的名称。这个头文件会根据需要被其他头文件自动包含:没有必要为了使用功
能测试宏而显式包含它。
根据上文定义的功能测试宏,
检查的宏。 这些宏的名称以两个下划线为前缀(例如,__USE_MISC)。程序不应
直接定义这些宏:相反,应使用上述恰当的功能测试宏。
示例
下面的程序可用于探索如何根据glibc的版本设置各种功能测试宏以及显式设置哪
些功能测试宏。下面的shell会话,在带有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
#include
#include
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);
}
推荐阅读
libc,standards
info libc下的“功能测试宏”部分。
/usr/include/features.h
版本记录
这个页面是Linux man-pages项目4.04版本的一部分。关于该项目的信息和bug
报道可以在该网站找到:http://www.kernel.org/doc/man-pages/。
2015-03-29