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

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

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

请注意,在许多系统上, log(2)可从的宏M_LN2获得。

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

 $ cat constant_call_opt.c #include  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 

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

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

这取决于。 如果编译器可以完全按照在运行时完成的方式进行数学运算,并且如果执行链接时优化,并且库是以某种中间forms保存的,那么可以完成。

大多数编译器都没有完成所有这些工作。

在库函数的情况下,一些编译器可能将这些函数实现为内在函数,这意味着编译器对编译时用常量替换调用的函数有足够的了解。 它是否会这样做取决于编译器。 在实践中,我经常注意到一些编译器不愿意在编译时预先计算浮点表达式,即使它们不涉及任何函数调用。

在一般情况下,通常它们不会也不能在编译时计算,假设编译器根本不了解这些函数以便能够在编译时计算它们。 也许他们有一些突出的运行时副作用?

某些编译器可能具有非标准的编译器相关扩展,允许用户向编译器提供有关函数的附加信息,以便编译器可以更好地优化函数调用,甚至可以确定给定调用是否可以用编译替换时间预先计算。 例如,GCC编译器支持constpure这样的函数属性 (GCC特定的扩展)。 如果参数在编译时是已知的,那么使用const属性调用函数理论上可以用编译时预计算替换。 虽然我不能说GCC是否能够真正做到这一点。

在C ++中(即使您的问题被标记为C语言),计划的新function是constexpr声明说明符,它具有类似的用途并且应该具有您描述的效果。

它们通常会在运行时计算出来(请参阅其他答案,了解如何内联它们),但我不一定会使用“浪费”这个词,除非它们有很多和/或代码执行了很多次。

不要只是放入常量值,而是创建一个#defineconst变量来表示值的含义( PILOG_2等)并使用它来代替。

例如:

 #define LOG_2 0.30102999566 

这不会进行任何计算,您可以根据您的环境(32位对64位)指定您希望或可以管理的精度值。

这在运行时发生,因为函数的代码仅在链接步骤期间变得可用(在编译步骤之后发生)。

要优化步骤,请使用在使用之前初始化的全局变量。