示例代码:
#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隐藏由用户标头与系统标头冲突引起的警告