c - 这个片段中的预处理是如何工作的?
问题描述
#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。
解决方案
预处理器被定义为对令牌流进行操作,而不是文本。您必须通读 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)
. --(5)
该标准在这方面没有提供任何自由度:将您的示例解析为有缺陷的 C 编译器。
当您要求编译器将预处理的源代码转储为文本时,标准未指定该文本的形式;通常,您得到的内容会根据需要插入空格,以便人类能够以与翻译阶段 7 相同的方式理解它。
推荐阅读
- node.js - Promise 链接和解析
- spring - 在 Junit 5 测试中注入 Spring 数据存储库
- python - 在字符串数组中查找某些元素不等于零的字符串
- c - 编译时出错:“二进制/的无效操作数(具有'short int *'和'int')”
- c++ - c++:为什么我不能为类“内部”的非常量静态成员赋值?
- visual-studio - MSBuild - 如何包含/排除目录?
- r - 无法在 R 中使用 rmarkdown 创建浮动目录
- angular - Angular Jquery Datatable 渲染按钮,单击事件不起作用
- solr - DSE 6.7 solr 搜索总是返回空
- powershell - PowerShell 访问按枚举逐项列出的多维数组