"#define _GNU_SOURCE"意味着什么?

Gui*_*i13 143 c posix gnu

今天我不得不使用这个basename()功能,而man 3 basename(这里)给了我一些奇怪的信息:

笔记

有两个不同版本的basename() - 上面描述的POSIX版本,以及GNU版本,后者可以使用

#define _GNU_SOURCE
#include <string.h>

我想知道这#define _GNU_SOURCE意味着什么:它是否污染了我用GNU相关许可证编写的代码?或者它只是用于告诉编译器类似" 嗯,我知道,这组函数不是POSIX,因此不可移植,但我还是想用它 ".

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

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

有人有一些指示可以给我吗?

R..*_*R.. 160

定义_GNU_SOURCE与许可证无关,与写入(非)可移植代码有关.如果你定义_GNU_SOURCE,你会得到:

  1. 访问许多非标准的GNU/Linux扩展功能
  2. 访问从POSIX标准中省略的传统功能(通常有充分的理由,例如被更好的替代品替换,或者与特定的传统实现相关联)
  3. 获得低级别的功能,可以是便携式的,但有时需要实现系统工具一样mount,ifconfig等等.
  4. 许多POSIX指定函数的破坏行为,其中GNU人员不同意标准委员会关于函数应该如何表现并决定做自己的事情.

只要您了解这些内容,定义就不应该是一个问题_GNU_SOURCE,但您应该避免定义它,而是定义_POSIX_C_SOURCE=200809L_XOPEN_SOURCE=700尽可能确保您的程序是可移植的.

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

  • 当然,每个人都知道定义`_GNU_SOURCE`的真正原因是为了得到[`strfry`](http://www.gnu.org/software/libc/manual/html_node/strfry.html)和[ `memfrob`](http://www.gnu.org/software/libc/manual/html_node/Trivial-Encryption.html#Trivial-Encryption). (69认同)
  • [本链接(https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html)到GNU C库文档提供了一些附加细节(例如,`的#define _GNU_SOURCE`是建议是"文件中的第一件事,仅在评论之前"). (4认同)
  • 我想成为一名付费程序员,将 *strfry* *memfrob* 和类似的设施移植到其他平台和工具链。 (2认同)
  • @user4815162342:此链接不再有效。 (2认同)

Chr*_*ris 6

来自谷歌的一些邮件列表:

查看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 启用了大量的编译标志

  • 它不会影响编译器的行为,只会影响标头中可见的原型和事物。 (21认同)

Bla*_*ade 6

让我再回答两点:

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

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

#ifdef _GNU_SOURCE
# define basename __basename_gnu
#else
# define basename __basename_nongnu
#endif
Run Code Online (Sandbox Code Playgroud)

现在,库只需要在这些名称下提供这两种行为.

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

通常相同的标题在不同的Unix版本中具有略微不同的内容,因此没有单一的正确内容,例如,<string.h>- 有许多标准(xkcd).有一整套宏来挑选你最喜欢的宏,所以如果你的程序需要一个标准,那么库就会符合这个标准.


P.P*_*.P. 5

有关可以全部启用的确切详细信息_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版本中;在2.09 2.1之前的glibc版本中是200109L;在1995年版本的glibc中是200106L); 199506L _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>
...
Run Code Online (Sandbox Code Playgroud)

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

$ gcc -D_GNU_SOURCE file.c
Run Code Online (Sandbox Code Playgroud)

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