交叉文件 #if 和 #endif - 它应该合法吗?
Cross-file #if and #endif - should it be legal?
根据C11标准,
A preprocessing directive of the form
# include "q-char-sequence" new-line
causes the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters.
所以如果我有一个头文件 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.
那么标准规定的行为是什么?
如果您阅读例如this C++ #include
reference the included file is first run through translation phases one to four, and phase four 是 运行 预处理器(递归)。
这意味着您包含的文件在 #if
和 #endif
方面必须是完整的。
这在 C 中也会发生。
阅读 C11 规范(ISO/IEC 9899:2011 [2012])后,我认为 是这样的:
编译器处于预处理器阶段 (phase 4) 并评估 #if 1
预处理器指令。条件评估为真,因此它进入条件内的块。看到 #include "test.h"
指令。
当编译器处理包含指令时,它会暂时停止处理当前文件,以处理包含的文件。在继续处理当前源文件之前,对包含文件的此处理会经过编译阶段 1 到 4(含)。
当包含的头文件本身的处理进入阶段4并开始处理#endif
指令时,它不会在递归中up inclusion stack to find the matching #if
,预处理器只查看当前堆栈帧(当前文件)。因此你得到第一个关于 no #if
的错误。该标准实际上对此没有任何说明。它基本上说的是 #if
必须有一个匹配的 #endif
。编译器不会在包含堆栈上查找匹配项 #if
似乎更多是一个实现细节。
无论如何,预处理器在第 4 阶段的第 3 步结束其对头文件的处理,即
At the end of this phase, all preprocessor directives are removed from the source.
所以当控件返回到源文件的预处理时,它实际包含的文件不包含任何预处理指令。基本上,所有包含的都是一个空文件。这导致了第二个错误,即 #if
没有 #endif
,因为确实没有。
clang
是正确的:#if/#endif
在不同文件中的这种拆分是不符合要求的。这是因为预处理器首先扫描文件的其余部分以找到相应的 #endif
,然后才解析保留的条件部分中存在的其他预处理器指令。
这是 C 标准的第 6.10.1 节 p6。
根据C11标准,
A preprocessing directive of the form
# include "q-char-sequence" new-line
causes the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters.
所以如果我有一个头文件 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.
那么标准规定的行为是什么?
如果您阅读例如this C++ #include
reference the included file is first run through translation phases one to four, and phase four 是 运行 预处理器(递归)。
这意味着您包含的文件在 #if
和 #endif
方面必须是完整的。
这在 C 中也会发生。
阅读 C11 规范(ISO/IEC 9899:2011 [2012])后,我认为 是这样的:
编译器处于预处理器阶段 (phase 4) 并评估 #if 1
预处理器指令。条件评估为真,因此它进入条件内的块。看到 #include "test.h"
指令。
当编译器处理包含指令时,它会暂时停止处理当前文件,以处理包含的文件。在继续处理当前源文件之前,对包含文件的此处理会经过编译阶段 1 到 4(含)。
当包含的头文件本身的处理进入阶段4并开始处理#endif
指令时,它不会在递归中up inclusion stack to find the matching #if
,预处理器只查看当前堆栈帧(当前文件)。因此你得到第一个关于 no #if
的错误。该标准实际上对此没有任何说明。它基本上说的是 #if
必须有一个匹配的 #endif
。编译器不会在包含堆栈上查找匹配项 #if
似乎更多是一个实现细节。
无论如何,预处理器在第 4 阶段的第 3 步结束其对头文件的处理,即
At the end of this phase, all preprocessor directives are removed from the source.
所以当控件返回到源文件的预处理时,它实际包含的文件不包含任何预处理指令。基本上,所有包含的都是一个空文件。这导致了第二个错误,即 #if
没有 #endif
,因为确实没有。
clang
是正确的:#if/#endif
在不同文件中的这种拆分是不符合要求的。这是因为预处理器首先扫描文件的其余部分以找到相应的 #endif
,然后才解析保留的条件部分中存在的其他预处理器指令。
这是 C 标准的第 6.10.1 节 p6。