【问题标题】:What does "#define _GNU_SOURCE" imply?“#define _GNU_SOURCE”是什么意思?
【发布时间】:2011-07-31 17:34:44
【问题描述】:

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

备注

basename() 有两个不同的版本 - 上面描述的 POSIX 版本和 GNU 版本,一个是在

#define _GNU_SOURCE
#include <string.h>

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

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

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

有人可以指点一下吗?

【问题讨论】:

    标签: c posix gnu


    【解决方案1】:

    定义_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真正原因是为了得到strfrymemfrob
    • This link 到 GNU C 库文档提供了一些额外的细节(例如,#define _GNU_SOURCE 被推荐为“文件中的第一个东西,前面只有 cmets”)。
    • @mckenzm:我想你想的是_FILE_OFFSET_BITS,而不是_GNU_SOURCE
    • 我想成为一名付费程序员,负责将 strfry memfrob 和类似便利设施移植到其他平台和工具链。
    • @user4815162342:此链接不再有效。
    【解决方案2】:

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

    来自 GNU 文档:

    宏:_GNU_SOURCE

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

    来自feature test macros 上的 Linux 手册页:

    _GNU_SOURCE

    定义这个宏(任何值)隐式定义 _ATFILE_SOURCE、_LARGEFILE64_SOURCE、_ISOC99_SOURCE、 _XOPEN_SOURCE_EXTENDED、_POSIX_SOURCE、_POSIX_C_SOURCE 与 值 200809L(2.10 之前的 glibc 版本中为 200112L; 199506L 在 2.5 之前的 glibc 版本中; glibc 版本中的 199309L 2.1 之前的版本)和 _XOPEN_SOURCE,值为 700(600 在 2.10 之前的 glibc 版本中; 500 之前的 glibc 版本 2.2)。此外,各种 GNU 特定的扩展也是 暴露。

    从 glibc 2.19 开始,定义 _GNU_SOURCE 也有如下效果 隐式定义_DEFAULT_SOURCE。在 glibc 版本中 在 2.20 之前,定义 _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,但任何宏都可以这样定义)。

    【讨论】:

      【解决方案3】:

      让我再回答两点:

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

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

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

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

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

      通常相同的标头在不同的 Unix 版本中具有略微不同的内容,因此没有单一的正确内容,例如 &lt;string.h&gt; — 有许多标准 (xkcd)。 有一整套宏可供您选择您最喜欢的一个,因此,如果您的程序需要一个标准,该库将符合该标准。

      【讨论】:

        【解决方案4】:

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

        查看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 启用了很多编译标志

        【讨论】:

        • 它不影响编译器的行为,只影响从头文件中可见的原型和东西。
        【解决方案5】:

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

        他们已经拿到了;标题被按主题分成文件,因此需要另一个维度来过滤。

        我一直在寻找信号编号到名称的转换。我在&lt;string.h&gt; 中找到了strsignal()。手册页说:

        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、在编译时或文件顶部设置。但这也会“激活”所有标题中的所有其他此类 ifdefed 声明。 (除非您为每个标题定义-取消定义)

        所以要显式导入一个(或其他)特殊功能,我现在就这样(复制粘贴。我离开了“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 &gt;&gt; 8) 给我TRAP 等等,没有#defines。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-09-24
          • 2020-10-02
          • 1970-01-01
          • 2019-08-09
          • 2021-12-25
          • 2023-04-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多