使用“#define _GNU_SOURCE” 是什么意思?

今天我必须要使用 basename 函数,使用man手册查询了一下这个函数 man 3 basename 发现一个奇怪的信息

名称

basename,dirname-分析路径名组件

简介

#include <libgen.h>
char *dirname(char *path);
char *basename(char *path);

警告
有两个不同的函数basename()-请参阅下面的。

函数dirname()和basename()将以空结尾的路径名字符串分解为目录和文件名组件。在通常情况下,dirname()返回最后一个“/”之前(但不包括在内)的字符串,basename()返回最后一个“/”之后的组件。尾随的“/”字符不算作路径名的一部分。

如果路径不包含斜杠,dirname()将返回字符串“.”,而basename()将返回路径的副本。如果path是字符串“/”,则dirname()和basename()都会返回字符串“/”。如果path是空指针或指向空字符串,则dirname()和basename()都返回字符串“.”。

将dirname()返回的字符串、一个“/” 和basename()返回的字符串连接起来,将生成完整的路径名.
dirname()和basename()都可能会修改路径的内容,因此在调用这两个函数时传入参数一定是一个路径的副本。

这些函数可能返回指向静态分配内存的指针,这些指针可能会被后续调用覆盖。或者,它们可以返回指向路径某一部分的指针,以便在不再需要函数返回的指针之前,不应修改或释放由路径引用的字符串。

下面的列表(取自SUS V2)显示了dirname()和basename()为不同路径返回的字符串:

path dirname basename
/usr/lib /usr lib
/usr/ / usr
usr . usr
/ / /
. . .
.

返回值

dirname()和basename()都返回指向以空结尾的字符串的指针。(不要将这些指针传递给free(3)。)

ATTRIBUTES

   For an explanation of the terms used in this section, see attributes(7).┌──────────────────────┬───────────────┬─────────┐│Interface             │ Attribute     │ Value   │├──────────────────────┼───────────────┼─────────┤│basename(), dirname() │ Thread safety │ MT-Safe │└──────────────────────┴───────────────┴─────────┘

注意

basename()有两个不同的版本————上面描述是posix版本,gnu版本是下面:

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <string.h>

GNU版本从不修改它的参数,当路径的结尾是一个斜杠时返回空字符串,特别是当它是“/”时。没有dirname()的GNU版本。
使用glibc,当包含<libgen.h>时,将获得basename()的POSIX版本,否则将获得GNU版本。

漏洞

在glibc实现中,这些函数的posix版本修改了path参数,并在使用诸如“/usr/”之类的静态字符串调用时修改产生段错误。

在glibc 2.2.1之前,dirname()的glibc版本没有正确地处理带有尾随“/”字符的路径名,如果给定了空参数,则会生成段错误。

例子

#include <libgen.h>
#include <stdio.h>
#define _GNU_SOURCE
#include <string.h>
int main(){char *dirc, *basec, *bname, *dname;char *path = "/etc/passwd";dirc = strdup(path);basec = strdup(path);dname = dirname(dirc);bname = basename(basec);printf("dirname=%s, basename=%s\n", dname, bname);return 0;
}

两个问题:

  1. 如果是这样,为什么不给人们提供不同的头文件,没有必要定义一些模糊的宏来获取函数的实现或者其他啊?
  2. 还有一些问题也让我抓狂:编译器怎么知道要连接那个函数到可执行文件? 也是使用 #define 的方式吗?

解答一

定义 _GNU_SOURCE 与许可证无关,与编写(非)可移植代码无关。如果您定义了“_GNU_SOURCE ”,您将得到:

  • 访问许多非标准的GNU/Linux扩展函数
  • 对POSIX标准中省略的传统功能的访问(通常是有充分理由的,例如被更好的替代方案替换,或者与特定的遗留实现绑定)
  • 访问不可移植的低级功能,但有时需要实现系统实用程序,如mount、ifconfig等。

对于许多POSIX指定的函数来说,行为是不正常的,GNU人员不同意标准委员会关于函数应该如何运行,并决定自己做一些事情。

只要你知道这些事情,定义 _GNU_SOURCE 就不是问题了,但是你应该避免定义它,而是在可能的时候定义POSIX_C_source=200809L或Xopen_source=700,以确保你的程序是可移植的。

尤其是,你不应该使用的来自GNU来源的东西是上面的2和4。

解答二

如果是这样,为什么不给人们提供不同的头文件,没有必要定义一些模糊的宏来获取函数的实现或者其他啊?

在不同的Unix版本中,同一个头部的内容通常稍有不同,因此没有单一的正确内容,例如,<string.h>—有许多标准(xkcd)。在一整套宏中选择你最想要的,这样,这个库可以满足不同人的标准。

还有一些问题也让我抓狂:编译器怎么知道要连接那个函数到可执行文件? 也是使用 #define 的方式吗?

一种常见的方法是根据 _GNU_SOURCE 是否被定义来有条件的 给标识符 basename 定义不同的名称:

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

这样库的实现中只要提供两种实现即可。

解答三

来自google的邮件列表

看看 glibc’s include/features.h:

定义了_GNU_SOURCE 表示可以使用
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 包括 GUN 扩展内容。

因此,它为gcc启用了大量编译标志

解答四

想详细了解 _GNU_SOURCE ,可以看一下下面的文档。

来自 GUN 文档

宏:_GNU_SOURCE

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

Linux 的man手册中的功能测试宏:

_GNU_SOURCE

定义这个宏(有任何值)隐式地定义了 _ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE, _XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE,其值为200809L(glibc版本2.10之前的200112L;glibc版本2.5之前的199506L;glibc版本2.1之前的199309L)和_XOPEN_SOURCE ,其值为700(600在2.10之前的glibc版本中;在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>
...

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

$ gcc -D_GNU_SOURCE file.c

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

使用“#define _GNU_SOURCE” 是什么意思?相关推荐

  1. linux c 宏定义 #define _GNU_SOURCE 含义

    今天我必须要使用 basename 函数,使用man手册查询了一下这个函数 man 3 basename 发现一个奇怪的信息 名称 basename,dirname-分析路径名组件 简介 #inclu ...

  2. 【编程基础の基础】“#define _GNU_SOURCE“或是在编译时“-D _GNU_SOURCE“代表了什么?有什么用

    概念 详细的信息可查看Linux手册 man feature_test_macros 从GNU的文档中: Macro: _GNU_SOURCE If you define this macro, ev ...

  3. fukk _GNU_SOURCE __USE_GNU

    #define _GNU_SOURCE #include "/usr/include/features.h" #ifndef __USE_GNU // 防御检查头文件是否已经启用G ...

  4. strstr函数头文件_C语言(函数)学习之strstr strcasestr

    一.strstr函数使用 [1] 函数原型 char *strstr(const char *haystack, const char *needle); [2] 头文件 #include [3] 函 ...

  5. linux内核添加c代码,如何从C代码加载Linux内核模块?

    Ciro Santill.. 19 最小的可运行示例 使用这个简单的参数打印机模块在QEMU + Buildroot VM和Ubuntu 16.04主机上进行了测试. 我们使用init_module/ ...

  6. 在Ubuntu 16.04.1 LTS上测试Linux AIO功能实录

    我们知道nginx中有libaio这项功能,为了研究AIO的一些常用接口用法,在网上找到一个例子,异步IO读取本地文件,亲自实践了一把,记录如下: 安装依赖库 在Ubuntu 16.04上需要事先安装 ...

  7. linux进程间通信:shell管道 | 的实现

    文章目录 介绍 重定向函数介绍 总结 linux terminal输入如下命令,其中"|"符号即为我们上文中所说的无名管道 介绍 正如我们上文中所描述的"|"无 ...

  8. ACCEPT()和ACCEPT4()

    ACCEPT 章节:Linux 程序员手册 (2) 更新:2010-09-10 到 易美翻译 翻译 名字 accept - 通过套接口接受一个连接 概要 #include Esys/types.h&g ...

  9. Nginx源码分析--数据对齐posix_memalign和memalign函数

    posix_memalign函数() /*  * 背景:  *      1)POSIX 1003.1d  *      2)POSIX 标明了通过malloc( ), calloc( ), 和 re ...

  10. posix_memalign

    翻译的<Linux system programming> 第八章 二 ;<Linux System Programming>中文版 对齐 数据的对齐(alignment)是指 ...

最新文章

  1. 高并发服务优化篇:从RPC预热转发看服务端性能调优
  2. 软件工程作业2.1:阐述对软件工程的理解,学完这门课自己能学到什么,学完后能做什么...
  3. 一个数据仓库时代开始--Hive
  4. android插件式换肤,Android学习之插件化换肤
  5. windows2008下配置iis时出现错误“由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。”...
  6. 使用Filter防止浏览器缓存页面或请求结果
  7. 显卡天梯图2022年4月 最新显卡性能排行天梯图
  8. 应用计算机测线性电阻伏安特性曲线,伏安特性曲线
  9. ESXI7.0下载地址
  10. Scratch的安装与界面介绍
  11. OJ每日一练——过滤多余的空格
  12. Three.js三角形Triangle
  13. python爬虫爬取steam,epic,origin平台游戏数据
  14. js 数组遍历时删除元素方法总结
  15. 李斌转让5000万股私人持有股份 完成蔚来用户信托设立
  16. 【织恋袜业】一双袜子的数字化之路——写在第十四届中国·大唐国际袜业博览会开幕前(下)
  17. 首批小程序出炉,小游戏?
  18. JAVA里面继承和接口
  19. windows64位系统完全卸载winpcap的方式
  20. 如何掌握二维码的扫描数据?

热门文章

  1. 深度点击率预估模型的One-Epoch过拟合现象剖析
  2. Black-Scholes期权定价模型
  3. mmdetection中使用训练好的模型单张图片推理并保存到文件夹
  4. 内边距怎么设置html,如何设置内边距
  5. echart 三维可视化地图_Echarts三维坐标系
  6. 管理学概念区分(行为科学、科学管理、古典管理理论)
  7. html主菜单和子菜单,刻录dvd光盘设置dvd菜单 只要子菜单可以吗 不要主菜单的
  8. GRUB和LILO的区别
  9. html 页面没有鼠标,网页上鼠标箭头不见了 电脑上不显示鼠标箭头怎么办?
  10. Vue中@click.stop与@click.prevent、@click.native