我无法找到处理下面案例的C预处理器的规则。如果你假设一个直接替换,这种情况甚至不应该编译,因为a=--1
。但是如果你假设用括号替换a=-(-1) = 1
。
#include <stdio.h>
#define ALPHA -1
#define BETA -ALPHA
int main(void) {
int a = BETA;
int b = -ALPHA; // this compiles too, why? b = --1
printf("%d\n",a); // 1
return 0;
}
答案 0 :(得分:2)
预处理是编译之前的阶段,它会生成一个预处理转换单元,它将作为编译器的输入。
其过程中的部分步骤是( From C99 5.1.1.2 ):
源文件已分解到预处理令牌。 (...)
- 醇>
执行预处理指令,扩展宏调用,(...)
正如您所见,标记化在宏调用之前,因此-ALPHA
将被视为2个单独预处理标记(* ie -
和{{ 1}} 1 )而不是你想象的2预处理令牌ALPHA
(--1
和--
)
在规则7之后:
- 空格字符分隔标记不是更长显着。 每个预处理令牌都转换为令牌。
醇>
因此编译器将获得令牌并忽略空格。
如果使用1
生成预处理文件,则空格没有任何意义,而您所看到的仅用于格式化为用户,并且无法反映CPP的实际内部行为。
来自 GCC CPP 5.4.0 1.3 :
代币不必用空格分隔,但它经常是 必要的以避免含糊不清(...)
一旦输入文件被分解为令牌,令牌边界永远不会 更改,除非使用'##'预处理运算符进行粘贴 一起代币
编译器不会重新标记预处理器的输出。每 预处理令牌成为一个编译器令牌。
汇总:
如果你写gcc -E
=&gt;代币是:
-ALPHA
标点符号 - 二进制减号
-
标点符号 - 二进制减号
-
常量 - 整数常量
如果你写1
=&gt;代币是:
--1
标点符号 - 递减运算符
--
常量 - 整数常量
递减运算符不应该与常量一起使用,这就是编译期间在这种情况下出错的原因。
1:1
标识符被替换(在第4阶段)由两个预处理标记ALPHA
和-
已识别< / strong>在宏定义中
答案 1 :(得分:1)
这是预处理完成后程序的样子。
int main(void) {
int a = - -1;
int b = - -1;
printf("%d\n",a);
return 0;
}
您可以使用-E
选项gcc
来查看此输出。
绝对不是--1
。注意额外的空间。
答案 2 :(得分:0)
首先要了解C预处理器不是编译过程的一部分。它只是替换过程,它告诉编译器在实际编译之前进行必要的预处理。
要了解更多,您必须阅读Macro Pitfalls。