根据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.
那么标准指定的行为是什么?
答案 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部分。