c - C 中的#define 是准确放置还是在前后留空格?

标签 c c-preprocessor

据我对 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

从输出的第二行可以清楚地看出没有发生递增和递减。

这意味着在替换 kkk 之后,它变成了:

t = (35*xx+ +-6+- -x*2)*4;

(如果是,那么计算就清楚了。)

我的关注点:它是 C 的标准还是只是未定义的行为?还是我做错了什么?

最佳答案

C 标准指定源文件被分析并解析为预处理器标记。当发生宏替换时,被替换的宏将被这些标记替换。替换不是文字文本替换。

C 2018 5.1.1.2 指定了翻译阶段(改写和总结,而不是精确引用):

  1. 物理源文件多字节字符映射到源字符集。三字母序列被单字符表示取代。

  2. 以反斜杠继续的行被合并。

  3. 源文件从字符转换为预处理标记和空白字符——每个可以作为预处理标记的字符序列都转换为预处理标记,每个注释变成一个空格。

  4. 执行预处理(执行指令并扩展宏)。

  5. 字符常量和字符串文字中的源字符被转换为执行字符集的成员。

  6. 相邻的字符串文字被连接起来。

  7. 空白字符被丢弃。 “每个预处理 token 都被转换成一个 token 。生成的标记在句法和语义上进行分析,并作为翻译单元进行翻译。” (引用的文本是我们认为的 C 编译的主要部分!)

  8. 程序被链接成为可执行文件。

因此,在第 3 阶段,编译器识别出 #define kk xx+k-x 由标记 #definekkxx+k-x。编译器也知道 definekk 之间以及 kkxx 之间有空格,但是这个空格本身不是预处理器 token 。

在第 4 阶段,当编译器替换源代码中的 kk 时,它会使用这些标记。 kk 被标记 xx+k-xk 替换为标记 +-6+-。组合起来,它们形成 xx++-6+---x

token 保持不变。它们不会被重新分析以将 ++ 组合在一起形成 ++

关于c - C 中的#define 是准确放置还是在前后留空格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60686692/

相关文章:

c - 在基于 C 的语言中,EOF 是如何生成和解释的?

c - 如何在交叉编译环境中检测 libc 名称和版本?

c++ - 编写宏

c++ - GCC、字符串化和内联 GLSL?

组合宏会产生错误

c - #define 多行字符串

c - 无跳转编程

c - 错误 : dereferencing pointer to incomplete type (Codeblocks, 在 C 中编程)

c - 宏依赖宏

创建节点列表