#define 中的常量计算会消耗资源吗?

do constant calculations in #define consume resources?

就我而言,c/c++中的常量和定义不会消耗内存和其他资源,但是当我们将定义用作宏并在其中进行一些计算时,情况就不同了.看看代码:

#include "math.h"
#define a 12.2
#define b 5.8
#define c a*b
#define d sqrt(c)

当我们在代码中使用变量 'd' 时,它是否会花费 CPU 的时间来计算 SQRT 和相加操作,或者这个值是在编译器中计算并只是在代码中替换? 如果是用CPU计算出来的,有没有在preprocessor里预先计算出来然后赋值在这里的常量?

要理解这一点,您需要了解 #define 的工作原理! #define 甚至不是编译器接收到的语句。它是一个预处理器指令,这意味着它由预处理器处理。 #define a b 字面上用 b 替换所有出现的 a。所以,你调用sqrt(c)多少次,就会被sqrt(a*b)代替多少次。现在,标准没有提到这样的事情是在运行时还是在编译时计算,而是留给各个编译器来决定。虽然,使用优化标志将 最终结果。更不用说,这些变量都不是类型安全的!

C标准没有规定使用d时需要的计算(即sqrt(12.2 * 5.8)是在编译时完成还是在运行时完成,留给各个编译器决定。

示例:

#define a 12.2
#define b 5.8
#define c a*b
#define d sqrt(c)

float foo() {
    return d;
}

int main(void)
{
    printf("%f\n", foo());
}

可能导致(使用 https://godbolt.org/ 和 gcc 10.2 -O0)

foo:
        pushq   %rbp
        movq    %rsp, %rbp
        movss   .LC0(%rip), %xmm0
        popq    %rbp
        ret
.LC1:
        .string "%f\n"
main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    [=11=], %eax
        call    foo
        pxor    %xmm1, %xmm1
        cvtss2sd        %xmm0, %xmm1
        movq    %xmm1, %rax
        movq    %rax, %xmm0
        movl    $.LC1, %edi
        movl    , %eax
        call    printf
        movl    [=11=], %eax
        popq    %rbp
        ret
.LC0:
        .long   1090950945

和 -O2

foo:
        movss   .LC0(%rip), %xmm0
        ret
.LC2:
        .string "%f\n"
main:
        subq    , %rsp
        movl    $.LC2, %edi
        movl    , %eax
        movsd   .LC1(%rip), %xmm0
        call    printf
        xorl    %eax, %eax
        addq    , %rsp
        ret
.LC0:
        .long   1090950945
.LC1:
        .long   536870912
        .long   1075892964

所以在这个例子中我们看到了一个编译时计算。根据我的经验,所有主要编译器都会这样做,但这不是 C 标准的要求。

as far as I'm concerned, constants and definitions in c/c++ do not consume memory and other resources,

这取决于你的意思。出现在可能在运行时评估的表达式中的常量必须以某种方式在程序中表示。在大多数情况下,这需要 space.

即使(在 C++ 中)constexpr可以在运行时计算,即使实现可以并且可能确实在编译时计算它们。

but that is a different story when we use definitions as macros and put some calculations inside it.

是的,它是不同的,因为宏在该术语的任何适用意义上都不是常量。

take a look at the code:

#include "math.h"
#define a 12.2
#define b 5.8
#define c a*b
#define d sqrt(c)

When we use the variable 'd' in our code,

d 不是变量。它是一个宏。无论它出现在那些宏定义范围内的什么地方,它都完全等同于出现在该点的表达式sqrt(12.2*5.8)

does it spend time for CPU to calculate the SQRT and add operations or this values are calculated in compiler and just replaced in the code?

两种情况都可能发生。这取决于您的编译器,可能取决于编译选项,也可能取决于翻译单元中的其他代码。预计算更有可能在更高的优化级别。

If it is calculated by CPU, is there anyway to be calculated beforehand in preprocessor and assigned as a constant here?

这样的计算不是预处理器语义的一部分本身。我们在现代 C 和 C++ 实现中对预处理器和编译器进行了某种程度的人为区分,如果执行预计算,则它将由编译器执行,而不是预处理器。

C 和 C++ 语言没有定义一种机制来强制在编译时执行此类计算,但您可以通过提高编译器的优化级别来提高它的可能性。或者在 C++ 中,可能有一种方法可以使用模板将表达式包装在计算其值的 constexpr 函数中,这很可能在编译时计算它。

但是,如果您想要一个常量,那么您始终可以选择手动预先计算它,并定义宏以扩展为实际常量。