首页 > 解决方案 > 这个片段中的预处理是如何工作的?

问题描述

#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。

标签: cmacrospreprocessor

解决方案


预处理器被定义为对令牌流进行操作,而不是文本。您必须通读 C 标准的所有部分5.1.16.46.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). --(5)该标准在这方面没有提供任何自由度:将您的示例解析为有缺陷的 C 编译器。

当您要求编译器将预处理的源代码转储为文本时,标准未指定该文本的形式;通常,您得到的内容会根据需要插入空格,以便人类能够以与翻译阶段 7 相同的方式理解它。


推荐阅读