交叉文件#if和#endif - 它应该合法吗?

时间:2016-10-14 03:15:57

标签: c++ c c-preprocessor c11 preprocessor-directive

根据C11标准,

  

表单

的预处理指令      

#include" q-char-sequence"新行

     

导致由"之间指定序列标识的源文件的全部内容替换该指令。分隔符。

因此,如果我有一个包含以下内容的头文件test.h

#endif

包含以下内容的源文件test.c

#if 1
#include "test.h"

是否应该通过替换test.h的内容按照标准通过预处理阶段?

但我不能用clang执行此操作,后者说:

In file included from test.c:2:
./test.h:1:2: error: #endif without #if
#endif
 ^
test.c:1:2: error: unterminated conditional directive
#if 1
 ^
2 errors generated.

那么标准指定的行为是什么?

2 个答案:

答案 0 :(得分:6)

如果您阅读例如this C++ #include reference包含的文件首先运行translation phases一到四,phase four运行预处理器(递归)。

这意味着您所包含的文件必须完整#if#endif

这也发生在C语言中。

在阅读C11规范(ISO / IEC 9899:2011 [2012])后,我认为发生的是:

编译器处于预处理器阶段(phase 4)并评估#if 1预处理器指令。条件的计算结果为true,因此它进入条件内的块。可以看到#include "test.h"指令。

当编译器处理include指令时,它会暂时停止处理当前文件,以处理包含的文件。在继续使用当前源文件之前,对包含文件的处理将经历编译阶段1到4(包括)。

当包含的头文件本身的处理进入第4阶段并开始处理#endif指令时,它不会在递归包含堆栈中 up 来查找匹配#if,预处理器只查看当前堆栈帧(当前文件)。因此,您收到关于否#if的第一个错误。该标准实际上没有说明这一点。它所说的基本上就是#if必须匹配#endif。编译器没有通过包含堆栈查找匹配的#if似乎更像是一个实现细节。

无论如何,预处理器在第4阶段的第3步结束对头文件的处理,这是

  

在此阶段结束时,将从源中删除所有预处理程序指令。

因此,当控件返回到源文件的预处理时,它实际包含的文件不包含任何预处理指令。基本上,所有包含的都是空文件。这导致第二个错误,#endif没有#if,因为实际上没有。{/ p>

答案 1 :(得分:0)

clang是正确的:不同文件中#if/#endif的这种分割是不一致的。这是因为预处理器首先扫描文件的其余部分以找到相应的#endif,然后才解析保留的条件部分中存在的其他预处理程序指令。

这是C标准的第6.10.1 p6部分。