“ # Definition _ GNU _ SOURCE”意味着什么?

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

笔记

Basename ()有两个不同的版本——上面描述的 POSIX版本和 GNU 版本版本,后者是后者

#define _GNU_SOURCE
#include <string.h>

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

如果是这样,为什么不给人们不同的头部,而是必须定义一些模糊的宏得到一个函数实现或其他?

还有一个问题困扰着我: 编译器如何知道哪个函数实现要链接到可执行文件?它也使用这个 #define吗?

有人有什么建议吗?

94451 次浏览

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

看看 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_SOURCE,你会得到:

  1. 访问许多非标准的 GNU/Linux 扩展函数
  2. 对 POSIX 标准中遗漏的传统函数的访问(通常是出于好的理由,比如被更好的替代方案替换,或者被绑定到特定的遗留实现)
  3. 访问不可移植的低级函数,但是您有时需要这些函数来实现系统实用程序,如 mountifconfig等。
  4. 许多指定于 POSIX 的函数都出现了问题,在这些函数中,GNU 人员不同意标准委员会关于函数应该如何表现的意见,并决定自己做自己的事情。

只要您意识到这些问题,定义 _GNU_SOURCE应该不成问题,但是您应该避免定义它,而是在可能的情况下定义 _POSIX_C_SOURCE=200809L_XOPEN_SOURCE=700,以确保您的程序是可移植的。

特别是,永远不会应该使用的 _GNU_SOURCE中的内容是上面的 # 2和 # 4。

让我再回答两个问题:

还有一个问题困扰着我: 编译器如何知道哪个函数实现要链接到可执行文件?它也使用这个 # 定义吗?

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

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

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

如果是这样,为什么不给人们不同的头部,而是必须定义一些模糊的环境变量得到一个功能实现或其他?

在不同的 Unix 版本中,同一个头的内容通常略有不同,因此对于 <string.h>ーー有许多标准(Xkcd) ,没有单一的正确内容。 有一整套宏来选择您最喜欢的宏,因此如果您的程序需要一个标准,那么库就会遵循这个标准。

有关 _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 2.10之前的 glibc 版本中的值200809L (200112L; 199506L 在 glibc 2.5之前的版本; 199309L 在 glibc ver- Sions before 2.1)和 _ XOPEN _ SOURCE,值为700(600 在2.10之前使用 glibc 版本; 在2.10之前使用 glibc 版本使用500 此外,还有各种特定于 GNU 的扩展 暴露了。

自 glibc 2.19以来,定义 _ GNU _ SOURCE 还具有 在 glibc 版本中隐式定义 _ DEFAULT _ SOURCE 在2.20之前,定义 _ GNU _ SOURCE 还具有 隐式定义 _ BSD _ SOURCE 和 _ SVID _ SOURCE。

注意 : _GNU_SOURCE需要定义为包含头文件的 之前,以便相应的头文件能够启用这些特性:

#define _GNU_SOURCE


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

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

$ gcc -D_GNU_SOURCE file.c

(-D不是特定于 _GNU_SOURCE的,但任何宏都是这样定义的)。

为什么不给人们不同的标题

他们已经得到了它们; 头被分成 按主题分类文件,所以需要另一个维度来过滤。

我正在寻找一个信号号到名字的转换。我发现 strsignal(),在 <string.h>。手册页说:

sigabbrev_np(), sigdescr_np():
_GNU_SOURCE                              <<< not default
strsignal():
From glibc 2.10 to 2.31:
_POSIX_C_SOURCE >= 200809L           <<< default, cf. XOPEN2K8 below
Before glibc 2.10:
_GNU_SOURCE

我从没真正喜欢过这个角色。sigabbrev_np()是包含在默认“特性”中的 没有string.h展示了如何:

#ifdef  __USE_XOPEN2K8
/* Return a string describing the meaning of the signal number in SIG.  */
extern char *strsignal (int __sig) __THROW;


# ifdef __USE_GNU
/* Return an abbreviation string for the signal number SIG.  */
extern const char *sigabbrev_np (int __sig) __THROW;
/* Return a string describing the meaning of the signal number in SIG,
the result is not translated.  */
extern const char *sigdescr_np (int __sig) __THROW;
# endif

__USE_GNU可以/应该通过 _GNU_SOURCE设置,在编译或 顶部文件时。但是,这也“激活”了所有标题中的所有其他类似的离散声明。(除非您定义-取消定义每个头)

因此,为了显式导入 就一个(或其他)特殊函数,我现在采用这种方式(复制-粘贴)。我离开了“ THROW”并更改了“ _ _ sig”) :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
extern const char *sigabbrev_np(int sig) __THROW;  /* __USE_GNU / _GNU_SOURCE */
#include <errno.h>
#include <elf.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
...

现在,sigabbrev_np(wstate >> 8)给我 TRAP等没有 # 定义。

我很难意识到 0x57f的意思是 OK,因为 5TRAP,而 0xb7f0x77fSEGVBUS——这取决于我设置断点的位置,有时在数千条指令之后。因为我没有后退指针..。