“#define _GNU_SOURCE”暗示什么?

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

笔记

basename()有两个不同的版本 – 上面描述的POSIX版本和GNU版本

#define _GNU_SOURCE
#include <string.h>

我想知道这个#define _GNU_SOURCE是什么意思:它是否#define _GNU_SOURCE了我用GNU相关许可证编写的代码? 或者它只是用来告诉编译器这样的东西,“ 我知道,这套函数不是POSIX,因此不能移植,但我仍然想用它 ”。

如果是这样,为什么不给人们不同的标题,而不必定义一些不起眼的macros来获得一个函数的实现或其他?

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

有人有指示给我?

定义_GNU_SOURCE与许可证和与编写(非)可移植代码有关的一切无关。 如果你定义_GNU_SOURCE ,你会得到:

  1. 访问大量非标准的GNU / Linux扩展function
  2. 访问POSIX标准中忽略的传统function(通常是出于很好的原因,比如replace为更好的select,或者与特定的传统实现绑定)
  3. 访问不能移植的底层函数,但有时需要实现像mountifconfig等系统实用程序。
  4. 在许多POSIX指定的函数中,破坏了行为,GNU人们不同意标准委员会关于函数的行为方式,并决定做自己的事情。

只要你知道这些事情,定义_GNU_SOURCE应该不是问题,但是你应该避免定义它,而是尽可能定义_POSIX_C_SOURCE=200809L_XOPEN_SOURCE=700 ,以确保你的程序是可移植的。

尤其是_GNU_SOURCE中你永远不会使用的东西是上面的#2和#4。

我再回答两点:

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

通常的做法是有条件地将#define标识符basename名称定义为不同的名称,具体取决于是否定义了_GNU_SOURCE 。 例如:

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

现在图书馆只需要提供这两个名称下的行为。

如果是这样,为什么不给人们不同的标题,而不必定义一些模糊的环境variables来获得一个函数的实现或其他?

通常在不同的Unix版本中,相同的头文件的内容略有不同,所以没有单一的正确的内容,例如<string.h> – 有很多标准( xkcd )。 有一整套的macrosselect你最喜欢的,所以如果你的程序需要一个标准,图书馆将符合这一点。

从一些邮件列表通过谷歌:

看看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_SOURCE,_SVID_SOURCE

所以它为gcc启用了大量的编译标志

有关_GNU_SOURCE全部启用的具体细节,文档可以提供帮助。

从GNU文档:

macros:_GNU_SOURCE

如果你定义了这个macros,包含所有内容:ISO C89,ISO C99,POSIX.1,POSIX.2,BSD,SVID,X / Open,LFS和GNU扩展。 在POSIX.1与BSD冲突的情况下,POSIX定义优先。

从functiontestingmacros的Linux手册页:

_GNU_SOURCE

定义这个macros(带有任何值)隐式定义了_ATFILE_SOURCE,_LARGEFILE64_SOURCE,_ISOC99_SOURCE,_XOPEN_SOURCE_EXTENDED,_POSIX_SOURCE,_POSIX_C_SOURCE的值为200809L(在2.10之前的glibc版本中的200112L;在2.5之前的glibc版本中的199506L;在2.1之前的glibc版本中的199309L) _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 ,以便相应的头文件启用这些function。 例如:

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

_GNU_SOURCE也可以使用-D标志进行编译:

 $ gcc -D_GNU_SOURCE file.c 

-D并不特定于_GNU_SOURCE但是可以用这种方式定义任何macros)。