常量表达式的数学函数是否在编译时预先计算?

cvb*_*cvb 12 c math compile-time

我倾向于使用常量表达式的数学函数来获得方便性和连贯性(即log(x)/log(2)代替log(x)/0.3...).由于这些函数实际上并不是语言本身的一部分,它们都没有定义math.h(仅声明),常量的函数会在编译时预先计算,还是会在运行时浪费计算?

for*_*ran 17

它取决于编译器和优化标志.正如@AndrewyT指出的那样,GCC能够指定哪些函数是常量和纯属的属性,在这种情况下答案是肯定的,它将内联结果,因为您可以轻松检查:

$ cat constant_call_opt.c 
#include <math.h>

float foo() {
        return log(2);
}

$ gcc -c constant_call_opt.c -S

$ cat constant_call_opt.s 
        .file   "constant_call_opt.c"
        .text
.globl foo
        .type   foo, @function
foo:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $4, %esp
        movl    $0x3f317218, %eax
        movl    %eax, -4(%ebp)
        flds    -4(%ebp)
        leave
        ret
        .size   foo, .-foo
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section        .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

没有函数调用那里,只是加载一个常量(0x3f317218 == 0.69314718246459961 == log(2))

虽然我现在没有任何其他编译器可以尝试,我认为你可以在所有主要的C编译器中期望相同的行为,因为它是一个微不足道的优化.


Ste*_*non 11

有些编译器会在编译时对它们进行评估,但这种行为并不能保证(这样做也可能会导致问题).您需要检查编译器并查看它的作用.

请注意,在许多系统上,log(2)可以从宏M_LN2中获取<math.h>.

  • 如果编译器知道日志没有副作用并且总是返回相同的值(例如,是一个'纯'函数),它可以在编译时评估它们.由于用户可以选择从数学库中替换函数,并且可以选择使用每次调用log(2)时没有返回相同值的函数或具有副作用的函数替换log,编译器无法评估它在编译时. (2认同)
  • 这是允许的,因为(尝试)替换任何标准函数的程序不再符合C程序. (2认同)