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

问题描述:

示例代码:为什么gcc和clang默默地允许一个标准的包含文件重新定义宏?

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

GCC和铛允许上面的代码片段来编译; PROT_NONE宏是从sys/mman.h中重新定义的,没有任何警告。看看实际的头文件,没有#undef会允许重定义。

这看起来像一个问题 - 虽然这种情况显然是设法显示问题,但似乎我的代码和系统头文件之间的标识符冲突可以默默忽略。 PROT_NONE的系统标题定义会覆盖我的定义,甚至不会提醒我存在潜在的问题。这似乎是某种特定的系统头文件;如果我自己尝试重新定义,我会得到适当的错误。

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

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

发生了什么事/动机

在这两个GNU和铛,警告抑制系统头。

clang user manual只是声明是这样的:当它们出现在系统头

警告被抑制。

...但gnu c preprocessor manual给出了以下理由:

头文件声明接口,操作系统和运行时库往往不能写在严格符合C.因此,GCC给出了系统中发现的代码接头特殊治疗。

缓解命令行

上是否有任何命令行开关,将导致这在编译阶段失败?

是的。使您的系统标题为非系统标题。

在clang中,只能使用--no-system-header-prefix x/y/z来做到这一点,其中x/y/z是从所有系统目录开始匹配的模式。例如,在你的情况下,你可以使用--no-system-headers sys;或者你可以选樱桃:--no-system-headers sys/mm(通过sys子目录包含的系统目录中以mm开头的所有文件;它只是一个前缀模式,而不是目录规范)。

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

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

您需要-nostdinc; -I进入系统包含路径的路径只会被忽略。

+0

感谢您的叮当声缓解;我测试了它,它适用于我的目的。 –

GCC suppresses warnings in system headers默认情况下。原因是用户通常无法对这些标题生成的警告进行任何操作,因为他们无法编辑代码来修复这些警告。您可以使用-Wsystem-headers启用这些警告。

对于你的具体例子,通过系统头重新定义一个未在系统头中定义的宏,GCC甚至可能会警告-Wno-system-headers(它现在有基础结构可以这样做)。有人已经提交了RFE:

+0

感谢您提供RFE的链接。这有助于我理解竞争性的论点。 –