C 预处理器指令是不是每次都重新计算?

Posted

技术标签:

【中文标题】C 预处理器指令是不是每次都重新计算?【英文标题】:Does C preprocessor directives recompute each time?C 预处理器指令是否每次都重新计算? 【发布时间】:2020-08-29 15:40:05 【问题描述】:

我有这行代码:

#define ALPHABET_SIZE 'z' - 'a' + 1

当我将鼠标悬停在代码中任何位置的 ALPHABET_SIZE 上时,它告诉我它扩展为 'z' - 'a' + 1。 所以我想知道每次我在代码中使用 ALPHABET_SIZE 时是否必须重新计算这个表达式?如果是这样,我该如何防止重新计算?

【问题讨论】:

可行,只是好奇。 我希望编译器会在编译时计算它,并且您的代码中只有 26 秒,除非您故意在关闭优化的情况下进行编译。 哦,你是说优化会自动处理它? 但要小心'z'-'a' +1。使用('z'-'a'+1),否则4*ALPHABET_SIZE之类的东西会给你带来意想不到的结果 【参考方案1】:
#define ALPHABET_SIZE 'z' - 'a' + 1

预处理器替换每个ALPHABET_SIZE

'z' - 'a' + 1

然后编译器很可能会执行Constant folding 优化,将计算替换为 26。


演示https://godbolt.org/z/Mo46db,表达式用gcc 10.2替换为26

【讨论】:

【参考方案2】:

C 标准仅指定程序的可观察行为,而不是它们在后台的工作方式。

是否每次都重新计算'z' - 'a' + 1 不会影响可观察行为,因此由实现决定。

通常,您可以期望合理的编译器在编译时计算结果,尤其是在启用优化时。

【讨论】:

【参考方案3】:

考虑以下程序:

#define ALPHABET_SIZE 'z' - 'a' + 1

#include <stdio.h>


int main(void)

    printf("%d\n", 2*ALPHABET_SIZE);
    printf("%d\n", ALPHABET_SIZE*2);

在我的 C 实现中,这会打印“148”和“27”。这是因为,在第一个 printf 中,2*ALPHABET_SIZE 被替换为 2*'z' - 'a' + 1,其计算结果为 (2*'z') - 'a' + 1,并且在第二个 printf 中,ALPHABET_SIZE*2 被替换为 'z' - 'a' + 1*2,即评估为'z' - 'a' + (1*2)。由于它们产生了两个不同的结果,因此证明了使用 C 语义的预处理不会用计算一次的单个表达式结果替换宏;它必须产生其他东西(实际上是一系列预处理器标记),随后在上下文中重新解释。

【讨论】:

以上是关于C 预处理器指令是不是每次都重新计算?的主要内容,如果未能解决你的问题,请参考以下文章

C中volatile关键字

22.预处理器

预指令

为啥 C 预处理器不忽略它跳过的块中的无效指令?

预处理器指令问题

C 基础 - 预处理器与C库