据我对 C 的了解,C 预处理器替换了 #define
中的文字。但是现在,我看到了,它在前后都留有空间。
我的解释是否正确,或者我正在做一些应该给出一些未定义行为的事情?
考虑以下 C 代码:
#include <stdio.h>
#define k +-6+-
#define kk xx+k-x
int main()
{
int x = 1029, xx = 4,t;
printf("x=%d,xx=%d\n",x,xx);
t=(35*kk*2)*4;
printf("t=%d,x=%d,xx=%d\n",t,x,xx);
return 0;
}
初始值为:x = 1029,xx = 4。现在让我们计算 t 的值。
t = (35*kk*2)*4;
t = (35*xx+k-x*2)*4; // replacing the literal kk
t = (35*xx++-6+--x*2)*4; // replacing the literal k
现在,xx = 4 的值将在下一条语句中增加 1 而 x 将减少 1 并变为 1028。所以,当前语句的计算:
t = (35*4-6+1028*2)*4;
t = (140-6+2056)*4;
t = 2190*4;
t = 8760;
但是上面代码的输出是:
x=1029,xx=4
t=8768,x=1029,xx=4
从输出的第二行可以清楚地看出没有发生递增和递减。
这意味着在替换 k 和 kk 之后,它变成了:
t = (35*xx+ +-6+- -x*2)*4;
(如果是,那么计算就清楚了。)
我的关注点:它是 C 的标准还是只是未定义的行为?还是我做错了什么?
最佳答案
C 标准指定源文件被分析并解析为预处理器标记。当发生宏替换时,被替换的宏将被这些标记替换。替换不是文字文本替换。
C 2018 5.1.1.2 指定了翻译阶段(改写和总结,而不是精确引用):
物理源文件多字节字符映射到源字符集。三字母序列被单字符表示取代。
以反斜杠继续的行被合并。
源文件从字符转换为预处理标记和空白字符——每个可以作为预处理标记的字符序列都转换为预处理标记,每个注释变成一个空格。
执行预处理(执行指令并扩展宏)。
字符常量和字符串文字中的源字符被转换为执行字符集的成员。
相邻的字符串文字被连接起来。
空白字符被丢弃。 “每个预处理 token 都被转换成一个 token 。生成的标记在句法和语义上进行分析,并作为翻译单元进行翻译。” (引用的文本是我们认为的 C 编译的主要部分!)
程序被链接成为可执行文件。
因此,在第 3 阶段,编译器识别出 #define kk xx+k-x
由标记 #
、define
、kk
、xx
、+
、k
、-
和 x
。编译器也知道 define
和 kk
之间以及 kk
和 xx
之间有空格,但是这个空格本身不是预处理器 token 。
在第 4 阶段,当编译器替换源代码中的 kk
时,它会使用这些标记。 kk
被标记 xx
、+
、k
、-
和x
,k
替换为标记 +
、-
、6
, +
和 -
。组合起来,它们形成 xx
、+
、+
、-
、6
、+
、-
、-
、-
和 x
。
token 保持不变。它们不会被重新分析以将 +
和 +
组合在一起形成 ++
。
关于c - C 中的#define 是准确放置还是在前后留空格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60686692/