C 编译器优化 - 涉及算术的宏

Posted

技术标签:

【中文标题】C 编译器优化 - 涉及算术的宏【英文标题】:C Compiler Optimization - Macros Involving Arithmetic 【发布时间】:2013-06-05 16:19:43 【问题描述】:

我正在和朋友讨论一个优化问题,需要一些帮助来找到这个问题的答案,希望我可以进一步阅读一些官方文档。

有人告诉我,在生产构建设置中编译一个简单程序时(即:CCOPTS+=-O4,无调试等),以下代码:

#define COEFFICIENT_F  (5.0f)
...
...
float f = 1.0f / COEFFICIENT_F;

...会自动优化成这样的:

#define COEFFICIENT_F  (5.0f)
...
...
#define INV_COEFFICIENT_F (0.2f)
float f = 1.0f * INV_COEFFICIENT_F;

虽然,如果我正在为调试构建进行编译(即:CCOPTS+=-O0 DEBUG=-g),则代码不会在预处理器级别优化此类操作。

所以,我的问题是双重的:

    传递给编译器的优化级别会影响预处理器做出的决定吗? 例如,GCC 是否会自动执行此类转换,包括在预处理时预先计算逆系数,并将其存储在我的代码的数据段中,以及乘以而不是除以倒数?李>

谢谢!

【问题讨论】:

看看两者的汇编输出,比较一下? fdiv vs fmul(或任何您系统的浮动操作码)将显示方式。虽然我不能直接回答你的两个问题...... Are constant C expressions evaluated at compile time or at runtime?的可能重复 【参考方案1】:

你的答案是:

    没有。预处理按照标准中的定义执行,不受任何优化级别的影响。

    您所说的优化不是在预处理时进行的,而是在从前端到代码生成器的漫长过程中。

【讨论】:

我什至不相信 2 是一种优化。无论优化器设置如何,编译器都会看到1.0 / 5.0,这将评估为0.2 @***foe 该优化称为常量折叠,诚然不是一个非常高级的优化,但尽管如此。一些前端(在预处理之后)可能会执行这样的优化,但我认为这是不好的做法。啊,是的,它可能在 -O0 时执行。 但这会随着优化器设置而改变吗?【参考方案2】:

这实际上取决于编译器的确切用法和确切情况。在您给出的确切示例中,如果编译器不知道1.0f/5.0f = 0.2f,就像1.0f*0.2f = 0.2f 一样(好吧,在这两种情况下,结果可能是0.1999996 或类似的东西。

现在,如果我们有一些编译器在编译过程中无法识别的数据:

 float f[] =  3.1415926f, 1.0f, 9.82f, 1.4142f ;
 float res[4]; 

 for(int i = 0; i < 4; i++)
    res[i] = f[i] / COEFFICIENT_F;

对比

 for(int i = 0; i < 4; i++)
    res[i] = f[i] * INV_COEFFICIENT_F;

它可能会产生一些差异(特别是在较低的优化级别,因为优化器不会用其他数学运算替换琐碎的数学运算,直到您至少达到 -O2)。

这会产生多大的差异取决于处理器架构。

要找出确切的差异,您必须编写一个小程序并测量它。 (做比四个更大的数字!)

【讨论】:

以上是关于C 编译器优化 - 涉及算术的宏的主要内容,如果未能解决你的问题,请参考以下文章

#define 用于在 C 中调试打印的宏?

C ++编译器能否优化使用用于将函数结果传递给另一个函数的虚拟变量?

使用速记 IF 的 C++ 编译器优化

C语言中怎样实现打印宏?(例如#define BBBBBBB 100000,然后输入为100000的时候打印出BBBBBB。

编译器优化:何为SLP矢量化

编译原理学习笔记代码优化