#include<stdio.h>
#define A -B
#define B -C
#define C 5
int main() {
printf("The value of A is %dn", A);
return 0;
}
我遇到了上面的代码。我认为经过预处理后,它会转化为
// code from stdio.h
int main() {
printf("The value of A is %dn", --5);
return 0;
}
这将导致编译错误。但是,代码可以正常编译并产生输出5
。
在这种情况下,如何对代码进行预处理,以免导致编译器错误?
PS:我正在Linux x86-64上使用gcc版本8.2.0。
答案 0 :(得分:5)
预处理器被定义为对令牌(而非文本)流进行操作。您必须通读C标准的所有5.1.1,6.4和6.10部分,以充分了解其工作原理,但关键点在5.1.1.1“翻译阶段”:在阶段3中,源文件被“分解为预处理令牌”;阶段4、5和6在这些令牌上运行;在阶段7中,“每个预处理令牌都转换为令牌”。那篇不确定的文章很关键:每个预处理令牌都变成一个准确的令牌。
这是什么意思,如果您从此源文件开始
#define A -B
#define B -C
#define C 5
A
然后,在翻译阶段4(宏扩展等)之后,您拥有的是三个预处理令牌的序列,
<punctuator: -> <punctuator: -> <pp-number: 5>
在翻译阶段7的开始,即成为
TK_MINUS TK_MINUS TK_INTEGER:5
,然后将其解析为表达式-(-(5))
而不是--(5)
。该标准在这方面没有任何余地:C编译器将您的示例解析为--(5)
有缺陷。
当您要求编译器将经过预处理的源作为文本转储时,标准未指定该文本的形式。通常情况下,您会获得必要的空格,以使人们能够像翻译阶段7一样理解空格。