为什么 gcc 和 clang 静默地允许标准包含文件重新定义宏?



示例代码:

#define PROT_NONE 99
#include <sys/mman.h>

gcc 和 clang 都允许编译上面的代码片段;PROT_NONE宏是在 sys/mman.h 中重新定义的,没有警告。 查看实际的头文件,没有允许重新定义的 #undef。

这似乎是一个问题 - 尽管这种情况显然是为了显示问题而精心设计的,但似乎可以静默忽略我的代码和系统头文件之间的标识符冲突。 PROT_NONE的系统标头定义覆盖了我的定义,甚至没有警告我存在潜在问题。 这似乎以某种方式特定于系统头文件;如果我尝试自己进行重新定义,我会得到正确的错误。

我的问题基本上是双重的:

  • 有人知道允许这种行为背后的动机吗?
  • 是否有任何命令行开关会导致编译阶段失败?
发生了什么

/动机

在 gnu 和 clang 中,警告在系统标头中被抑制。

clang 用户手册只是声明了这一点:

当警告出现在系统标头中时,将禁止显示警告。

。但是 GNU C 预处理器手册给出了以下理由:

声明操作系统和运行时库接口的头文件通常不能用严格符合 C 语言编写。因此,GCC 对系统标头中的代码进行了特殊处理。

命令行上的缓解措施

是否有任何命令行开关会导致编译阶段失败?

是的。 使系统标头成为非系统标头。

在 clang 中,您只能使用--no-system-header-prefix x/y/z来执行此操作,其中 x/y/z 是从所有系统目录开始匹配的模式。 例如,在您的情况下,您可以使用--no-system-headers sys;或者你可以进一步挑选:--no-system-headers sys/mm(系统目录中的所有文件都包含在以mm开头的sys子目录中;它只是一个前缀模式,而不是目录规范(。

在 gcc 中,这有点棘手。 默认情况下,系统标头只是系统目录中的标头,无法将特定目录排除为系统目录。 但是,您可以使用-nostdinc放弃所有系统目录,并将它们作为常规包含目录重新添加。 例如:

gcc -nostdinc -I/usr/include -I/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include ...

你需要-nostdinc; 进入系统包含路径-I路径最终会被忽略。

默认情况下,GCC 会禁止显示系统标头中的警告。 原因是用户通常无法对这些标头生成的警告执行任何操作,因为他们无法编辑代码来修复这些警告。 您可以使用-Wsystem-headers启用这些警告。

对于您的特定示例,重新定义系统标头中未在系统标头中定义的宏,GCC 即使使用-Wno-system-headers也应该发出警告(它现在具有执行此操作的基础结构(。 有人已经提交了RFE:

-
  • Wno-system-headers隐藏由用户标头与系统标头冲突引起的警告

最新更新