Hai*_*ang 2 c c++ c-preprocessor preprocessor-directive c11
根据C11标准,
表单的预处理指令
#include"q-char-sequence"换行符
导致由"分隔符"之间的指定序列标识的源文件的全部内容替换该指令.
所以,如果我有一个头文件test.h包含:
#endif
Run Code Online (Sandbox Code Playgroud)
一个源文件test.c包含:
#if 1
#include "test.h"
Run Code Online (Sandbox Code Playgroud)
是否应该根据标准通过更换现有内容来通过预处理阶段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.
Run Code Online (Sandbox Code Playgroud)
那么标准指定的行为是什么?
如果您阅读例如此C++ #include引用,则所包含的文件首先通过转换阶段 1到4 运行,而第4阶段运行预处理器(递归地).
这意味着您包含的文件必须完整,#if并且#endif.
这也发生在C语言中.
在阅读C11规范(ISO/IEC 9899:2011 [2012])后,我认为发生的是:
编译器处于预处理器阶段(阶段4)并评估#if 1预处理器指令.条件计算结果为true,因此它进入条件内的块.有看到#include "test.h"指令.
当编译器处理include指令时,它会暂时停止处理当前文件,以处理包含的文件.在继续当前源文件之前,对包含文件的处理经历编译阶段1到4(包括).
当包含的头文件本身的处理涉及到第四阶段,并开始处理#endif指令,那么它不走了在递归列入堆栈找到匹配的#if,预处理器只着眼于当前堆栈帧(当前文件).因此,您得到关于否的第一个错误#if.该标准实际上没有说明这一点.所有它说,基本上,是#if必须有匹配#endif.编译器没有通过包含堆栈来查找匹配#if似乎更像是一个实现细节.
无论如何,预处理器在阶段4中用步骤3结束其对头文件的处理,即
在此阶段结束时,将从源中删除所有预处理程序指令.
因此,当控件返回到源文件的预处理时,它实际包含的文件不包含任何预处理指令.基本上,所有包含的都是空文件.这导致了第二个错误,没有#endif了#if,因为真的没有.