GCC将为运行时或编译输出留下固定值的算术吗?

Will GCC leave arithmetic with fixed values for run-time or compile the output?

本文关键字:运行时 编译 输出 GCC      更新时间:2023-10-16

我想知道GCC是否会在运行时留下固定值的算术,或者它是否会将其设置为它的答案,例如

const float halfPi = M_PI/2;

它会"煮沸"方程并设置

const float halfPi = 1.57079;

还是把算术留给运行时?

嗯…如果我们讨论积分,答案将是明确的(在一般术语常数折叠下)。即使是冗长的计算也可以在编译时完成。这实际上是模板非类型参数求值和(现在)constexpr变量所需要的。

对于浮点表示,随着计算变得更复杂,事情也变得更复杂了。问题是,对于相同的基本输入,不同大小(以及精度)的浮点表示将产生不同的结果。

要理解为什么,假设float最多有5位精度:

   5.0000 + 0.00001
-> 5.00001
-> 5.0000 (truncation to 5 digits)
   5.0000 + 0.00001 + ... + 0.00001 (10 times)
-> 5.0000 + 0.00001 + ... + 0.00001 (9 times)
-> 5.0000 + 0.00001 + ... + 0.00001 (8 times)
-> ...
-> 5.0000

奇怪……对吧?如果编译是在运行时完成的,那么结果可能会根据是否使用寄存器(具有更大的位宽)而变化。

因此,常量折叠是否发生可能取决于所使用的优化标志集。例如,对于gcc,这可能由-freciprocal-math控制(真的不知道)。因为即使编译器肯定可以这样做,您也可能告诉它不要这样做(不知不觉地)。

所以唯一确定的测试方法是检查编译器的输出;要么检查目标代码,要么要求编译器发出程序集。并且您需要检查该输出是否包含您使用的每个选项组合。

今天是你的幸运日,因为你发现Agner Fog和他的惊人的深度c++手册!如果你看一下这篇文章的8.2节,你会发现基本上所有的编译器都能进行常量折叠。

虽然要确保它在编译器选项的特定情况下确实发生,但您应该按照上面的建议检查程序集输出(使用-S)。我喜欢把像asm("MY_LABEL:");这样的东西放在代码附近,以便于找到,但请记住,这可以改变代码的含义,因此编译器如何解释它。在这种情况下,我不相信它会改变什么。