“ #define _GNU_SOURCE”意味着什么?


152

今天,我不得不使用该basename()函数,并且man 3 basename这里)给了我一些奇怪的信息:

笔记

basename()有两种不同的版本- 上面描述的POSIX版本和GNU版本,其中一种

#define _GNU_SOURCE
#include <string.h>

我想知道这#define _GNU_SOURCE是什么意思:它污染了我使用GNU相关许可证编写的代码吗?或者它只是用来告诉编译器,例如“ 嗯,我知道,这组函数不是POSIX,因此不是可移植的,但是我还是想使用它 ”。

如果是这样,为什么不给人们提供不同的标题,而不必定义一些晦涩的宏来获得一个函数实现或另一个实现呢?

有些东西也困扰着我:编译器如何知道与可执行文件链接的函数实现?它也使用这个#define吗?

有人给我一些指示吗?

Answers:


172

定义_GNU_SOURCE与许可证无关,与编写(非)便携式代码无关。如果定义_GNU_SOURCE,您将获得:

  1. 访问许多非标准的GNU / Linux扩展功能
  2. 访问POSIX标准中省略的传统功能(通常是有充分的理由,例如被更好的替代品替代,或者与特定的旧版实现相关联)
  3. 获得低级别的功能,可以是便携式的,但有时需要实现系统工具一样mountifconfig等等。
  4. 许多POSIX特定功能的行为都被破坏了,GNU成员就这些功能应该如何行为与标准委员会不同意,并决定自行完成工作。

只要您知道这些事情,定义并不是什么问题_GNU_SOURCE,但是应该避免定义它,而应该定义它,_POSIX_C_SOURCE=200809L或者_XOPEN_SOURCE=700在可能的情况下确保您的程序可移植。

特别是,_GNU_SOURCE永远不应该使用的东西是上面的#2和#4。


71
当然,每个人都知道定义的真正原因_GNU_SOURCE是为了获得strfrymemfrob
user4815162342'3

5
该指向 GNU C库文档的链接提供了一些其他详细信息(例如,#define _GNU_SOURCE建议将其作为“文件中的第一件事,仅在注释之前”)。
亚历山大·波兹涅夫

无关紧要,但用于扩展32位目标的2GB文件大小限制。
mckenzm

1
@mckenzm:我想您是在想_FILE_OFFSET_BITS,不是_GNU_SOURCE
R .. GitHub停止帮助ICE,

我想成为strfry memfrob和类似便利设施移植到其他平台和工具链的付费程序员。
马西莫

6

让我回答另外两点:

有些东西也困扰着我:编译器如何知道与可执行文件链接的函数实现?它是否也使用此#define?

一种常见的方法是根据是否定义有条件地将#define标识符标识basename为不同的名称_GNU_SOURCE。例如:

#ifdef _GNU_SOURCE
# define basename __basename_gnu
#else
# define basename __basename_nongnu
#endif

现在,该库只需要使用这些名称提供两种行为即可。

如果是这样,为什么不给人们提供不同的标题,而不必定义一些晦涩的环境变量来获得一个功能实现或另一个功能实现呢?

通常,在不同的Unix版本中,同一标头的内容略有不同,因此,例如, <string.h>存在许多标准(xkcd)。有一组完整的宏可以选择您喜欢的宏,因此,如果您的程序需要一个标准,则库将符合该标准。


6

有关可以全部启用的确切详细信息_GNU_SOURCE,文档可以提供帮助。

从GNU文档中:

巨集:_GNU_SOURCE

如果定义此宏,则将包括所有内容:ISO C89,ISO C99,POSIX.1,POSIX.2,BSD,SVID,X / Open,LFS和GNU扩展。在POSIX.1与BSD冲突的情况下,POSIX定义优先。

功能测试宏的Linux手册页中:

_GNU_SOURCE

定义此宏(具有任何值)将隐式定义_ATFILE_SOURCE,_LARGEFILE64_SOURCE,_ISOC99_SOURCE,_XOPEN_SOURCE_EXTENDED,_POSIX_SOURCE,_POSIX_C_SOURCE,其值分别为200809L(在2.10 2.1之前的glibc版本中的200112L在glibc中;在2001年之前的glibc版本中是2001年的glibc版本中的200112L; 199506L的版本是早于glibc的glibc版本中的1995年版本); _XOPEN_SOURCE的值为700(在2.10之前的glibc版本中为600;在2.2之前的glibc版本中为500)。此外,还公开了各种特定于GNU的扩展。

从glibc 2.19开始,定义_GNU_SOURCE也具有隐式定义_DEFAULT_SOURCE的作用。在2.20之前的glibc版本中,定义_GNU_SOURCE也具有隐式定义_BSD_SOURCE和_SVID_SOURCE的作用。

注意_GNU_SOURCE需要包含头文件之前进行定义以便相应的头启用功能。例如:

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
...

_GNU_SOURCE也可以使用-D标志启用每个编译:

$ gcc -D_GNU_SOURCE file.c

-D不特定_GNU_SOURCE于此,而是以这种方式定义任何宏)。


4

通过Google的一些邮件列表:

查看glibc的include / features.h:

_GNU_SOURCE以上所有内容,以及GNU扩展。

这意味着它可以启用所有这些功能:

STRICT_ANSI,_ISOC99_SOURCE,_POSIX_SOURCE,_POSIX_C_SOURCE,_XOPEN_SOURCE,_XOPEN_SOURCE_EXTENDED,_LARGEFILE_SOURCE,_LARGEFILE64_SOURCE,_FILE_OFFSET_BITS = N,_BSD_CE

因此,它为gcc启用了很多编译标志


21
它不会影响编译器的行为,只会影响标头中可见的原型和内容。
Spudd86
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.