鉴于这段 C 代码:
char s[] =
"start"
#ifdef BLAH
"mid"
#endif
"end";
预处理器的输出应该是多少?换句话说,实际编译器应该接收并能够处理什么?为了缩小可能性,让我们坚持使用C99。
我看到一些预处理器输出了这个:
#line 1 "tst00.c"
char s[] =
"start"
#line 9
"end";
或者这个:
# 1 "tst00.c"
char s[] =
"start"
# 7 "tst00.c"
"end";
gcc -E输出:
# 1 "tst00.c"
# 1 "<command-line>"
# 1 "tst00.c"
char s[] =
"start"
"end";
即使使用 -fpreprocessed 选项,gcc也可以很好地编译所有上述预处理代码,这意味着不需要进行进一步的预处理,因为所有这些都已经完成。
混淆源于1999年 C 标准的措辞:
5.1.1.2 Translation phases
1 The precedence among the syntax rules of translation is specified by the following
phases.
...
4. Preprocessing directives are executed, macro invocations are expanded, and
_Pragma unary operator expressions are executed. ... All preprocessing directives are
then deleted.
...
6. Adjacent string literal tokens are concatenated.
7. White-space characters separating tokens are no longer significant. Each
preprocessing token is converted into a token. The resulting tokens are syntactically
and semantically analyzed and translated as a translation unit.
换句话说,#line
指令出现在相邻字符串文字之间是否合法?如果是,则意味着实际编译器必须执行另一轮字符串文字串联,但标准中未提及。
或者我们只是处理非标准的编译器实现,包括gcc?
答案 0 :(得分:1)
为了人类读者和任何可能尝试使用文本形式的工具,我们会添加您从GCC -E(或兼容工具)获得的#line
或# 1
行。预处理器的输出。它们只是为了方便。
通常,是的,指令可能出现在连接的字符串文字标记之间。 #line
与您示例中的#ifdef
没有区别。
或者我们只是处理非标准的编译器实现,包括gcc?
-E
和-fpreprocessed
模式未标准化。标准预处理器始终将其输出提供给编译器,而不是文本文件。此外:
预处理器的输出没有标准的文本表示。
插入#line
指令的原因是,在再次预处理之前,您可能插入到已经预处理的文件中的任何__LINE__
和__FILE__
宏都将正确扩展。也许,在编译这样的文件时,编译器可能会在报告错误时注意并使用这些值。 “预处理文本文件”的使用是非标准的,通常不鼓励。