“#define _GNU_SOURCE”是什么意思?意味着?

发布于 2024-10-31 03:57:55 字数 763 浏览 5 评论 0原文

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

注释

basename() 有两个不同的版本 - 上面描述的 POSIX 版本,以及 GNU 版本,后者是在 < /p>

#define _GNU_SOURCE
#include

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

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

还有一些事情让我烦恼:编译器如何知道哪个函数实现与可执行文件链接?它也使用这个#define吗?

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

Today I had to use the basename() function, and the man 3 basename (here) gave me some strange message:

Notes

There are two different versions of basename() - the POSIX version described above, and the GNU version, which one gets after

#define _GNU_SOURCE
#include <string.h>

I'm wondering what this #define _GNU_SOURCE means: is it tainting the code I write with a GNU-related license? Or is it simply used to tell the compiler something like "Well, I know, this set of functions is not POSIX, thus not portable, but I'd like to use it anyway".

If so, why not give people different headers, instead of having to define some obscure macro to get one function implementation or the other?

Something also bugs me: how does the compiler know which function implementation to link with the executable? Does it use this #define as well?

Anybody have some pointers to give me?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

爱已欠费 2024-11-07 03:57:55

定义 _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。

Defining _GNU_SOURCE has nothing to do with license and everything to do with writing (non-)portable code. If you define _GNU_SOURCE, you will get:

  1. access to lots of nonstandard GNU/Linux extension functions
  2. access to traditional functions which were omitted from the POSIX standard (often for good reason, such as being replaced with better alternatives, or being tied to particular legacy implementations)
  3. access to low-level functions that cannot be portable, but that you sometimes need for implementing system utilities like mount, ifconfig, etc.
  4. broken behavior for lots of POSIX-specified functions, where the GNU folks disagreed with the standards committee on how the functions should behave and decided to do their own thing.

As long as you're aware of these things, it should not be a problem to define _GNU_SOURCE, but you should avoid defining it and instead define _POSIX_C_SOURCE=200809L or _XOPEN_SOURCE=700 when possible to ensure that your programs are portable.

In particular, the things from _GNU_SOURCE that you should never use are #2 and #4 above.

安穩 2024-11-07 03:57:55

有关 _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 之前的 glibc 版本中为 200112L;
2.5 之前的 glibc 版本中为 199506L; 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>
...

还可以使用 -D 标志在每次编译时启用 _GNU_SOURCE:(

$ gcc -D_GNU_SOURCE file.c

-D 并非特定于 _GNU_SOURCE 但任何宏都可以这样定义)。

For exact details on what are all enabled by _GNU_SOURCE, documentation can help.

From the GNU documentation:

Macro: _GNU_SOURCE

If you define this macro, everything is included: ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X/Open, LFS, and GNU extensions. In the cases where POSIX.1 conflicts with BSD, the POSIX definitions take precedence.

From the Linux man page on feature test macros:

_GNU_SOURCE

Defining this macro (with any value) implicitly defines
_ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE,
_XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE with
the value 200809L (200112L in glibc versions before 2.10;
199506L in glibc versions before 2.5; 199309L in glibc ver‐
sions before 2.1) and _XOPEN_SOURCE with the value 700 (600
in glibc versions before 2.10; 500 in glibc versions before
2.2). In addition, various GNU-specific extensions are also
exposed.

Since glibc 2.19, defining _GNU_SOURCE also has the effect of
implicitly defining _DEFAULT_SOURCE. In glibc versions
before 2.20, defining _GNU_SOURCE also had the effect of
implicitly defining _BSD_SOURCE and _SVID_SOURCE.

Note: _GNU_SOURCE needs to be defined before including header files so that the respective headers enable the features. For example:

#define _GNU_SOURCE

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

_GNU_SOURCE can be also be enabled per compilation using -D flag:

$ gcc -D_GNU_SOURCE file.c

(-D is not specific to _GNU_SOURCE but any macro be defined this way).

逆夏时光 2024-11-07 03:57:55

我再回答两点:

还有件事让我烦恼:编译器如何知道哪个函数实现与可执行文件链接?它也使用这个#define吗?

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

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

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

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

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

Let me answer two further points:

Something also bugs me: how does the compiler know which function implementation to link with the executable? Does it use this #define as well?

A common approach is to conditionally #define identifier basename to different names, depending on whether _GNU_SOURCE is defined. For instance:

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

Now the library simply needs to provide both behaviors under those names.

If so, why not give people different headers, instead of having to define some obscure environment variable to get one function implementation or the other?

Often the same header had slightly different contents in different Unix versions, so there is no single right content for, say, <string.h> — there are many standards (xkcd).
There's a whole set of macros to pick your favorite one, so that if your program expects one standard, the library will conform to that.

情痴 2024-11-07 03:57:55

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

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

From some mailing list via google:

Look at glibc's include/features.h:

_GNU_SOURCE All of the above, plus GNU extensions.

Which means it enables all this:

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

So it enables a whole lot of compiling flags for gcc

迷鸟归林 2024-11-07 03:57:55

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

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

我正在寻找信号数字到名称的转换。我在 中找到了 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 >> 8) 给我 TRAP 等,无需#defines。

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

why not give people different headers

They already got them; the headers are divided by topic into files, so it takes another dimension to filter.

I was looking for a signal number-to-name conversion. I found strsignal(), in <string.h>. The man page says:

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

I had never really cared for this part at all. sigabbrev_np() is not included in the default "features". string.h shows how:

#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 can/should be set via _GNU_SOURCE, at compilation or top of the file. But that "activates" all other such ifdeffed declarations in all headers, too. (Unless you define-undefine per header)

So to explicitly import just one (or the other) special function, I go like this for now (copy-paste. I left the "THROW" and changed "__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>
...

Now sigabbrev_np(wstate >> 8) gives me TRAP etc. without #defines.

I had a hard time realizing that 0x57f means OK because 5 is TRAP, but 0xb7f and 0x77f are SEGV and BUS --- which I got depending on where I set the breakpoint, sometimes after thousands of instructions. Because I did not step back the intruction pointer...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文