编译器是否会简化按顺序执行多次的操作

Will an operation done several times in sequence be simplified by compiler?

本文关键字:执行 操作 顺序 是否 编译器      更新时间:2023-10-16

这个问题我已经有很长时间了,但从来不知道去哪里找。如果某个操作被编写了很多次,编译器会简化它,还是会运行完全相同的操作并获得完全相同的答案?

例如,在下面的类似c的伪代码中,(i%3)*10重复了很多次。

for(int i=0; i<100; i++) {
array[(i%3)*10] = someFunction((i%3)*10);
int otherVar = (i%3)*10 + array[(i%3)*10];
int lastVar = (i%3)*10 - otherVar;
anotherFunction(lastVar);
}

我知道变量更适合视觉目的,但它也更快吗?(i%3)*10每个循环计算 5 次吗?

在某些情况下,我不知道使用变量还是离开原始操作更快。

编辑:在win 10上使用gcc(MinGW.org GCC-8.2.0-3)8.2.0

执行哪些优化取决于编译器、指定的编译器优化标志和体系结构。

以下是针对您的示例的一些可能的优化:

  • 循环展开 这使得二进制文件更大,因此是一种权衡;例如,您可能不希望在内存非常少的微型处理器上执行此操作。
  • 通用子表达式消除 (CSE) 您可以非常确定您的(i % 3) * 10在每次循环迭代中只会执行一次。

关于您对视觉清晰度与优化的关注:在处理像您这样的"本地情况"时,您应该关注代码清晰度。

优化收益通常是在更高的级别上进行的;例如,在您使用的算法中。

关于优化有很多话要说;以上只是几个开场白。你对事物的工作方式感兴趣是件好事,因为这对一个优秀的(C/C++)程序员来说很重要。

当然,你应该删除代码中存在的混淆:

for (int i = 0; i < 100; ++i) {
int i30 = i % 3 * 10;
int r = someFunction(i30);
array[i30] = r;
anotherFunction(-r);
}

突然间,它看起来简单了很多。

留给编译器(使用适当的选项)来优化您的代码,除非您发现在测量后实际上必须伸出援手。
在这种情况下,展开三次对于编译器来说是一个好主意。尽管内联可能总是显示更好的选择。

是的,按顺序执行多次的操作将由编译器优化。

更详细地说,所有主要的编译器(GCC、Clang 和 MSVC)都将(i%3)*10的值存储到临时(暂存、垃圾)寄存器中,然后在再次使用等效表达式时使用该值。
这种优化称为GCSE(GNU公共子表达式消除),否则称为CSE。
这占用了计算循环所需的时间