编译器会为循环优化吗?

时间:2016-09-19 12:10:06

标签: c++ c gcc optimization

在C或C ++中,如果编译器遇到for循环,其中计数器从0计数到n,而n是变量(不是函数调用,以及 NOT A CONSTANT ,编译器是否会优化循环,检查变量n(绑定变量)是否会在循环期间被更改(访问以进行写入,例如:n可以是在循环之前计算的字符串长度,通过优化这里我的意思是将其值复制到寄存器以避免内存访问?

以下是一个例子:

for (int c = 0; c < n; c++) {
    // do something not related to n
}

编译器会注意到并优化它吗?

4 个答案:

答案 0 :(得分:8)

  

c / c ++编译器会通过检查变量n(绑定变量)是否会在循环期间更改来优化循环

&#34; as-if&#34;规则允许编译器重新排序或重写代码,只要可观察的效果是&#34;好像&#34;它执行了你写的代码。

此处的关键字是&#34;可观察&#34;。除非可以证明n在执行循环体期间不能改变,否则循环必须为每次迭代重新计算c < n

如果编译器可以访问循环中的所有代码(例如,它在同一编译单元中定义,或者全局优化在链接期间具有另一种外观,则n永远不会被别名一个引用或指针)然后它很可能证明n没有改变。

在这种情况下,你不应该对以某种方式优化循环感到惊讶。

答案 1 :(得分:2)

结果取决于正在使用的编译器。

编译器可以使用n的处理器寄存器,您仍然可以在循环内修改n。无论如何,最小化的优化是可能的。

将变量的值放在处理器寄存器中可能会导致&#39;别名&#39;问题如果你有一个指向n的指针,你使用指针间接改变n的值。

例如:

int n = 4;
int *nptr = &n;
for(int i = 0; i < n; ++i)
  --*nptr;

编译器必须知道nptr是n的别名,因此必须在每次访问时从内存中读取n,但在许多情况下编译器根本无法知道n和nptr之间的关系。

您可以使用volatile关键字来阻止编译器优化变量(即volatile int n = 4;

答案 2 :(得分:1)

您应该尝试编译并自己查看。编译器中的优化取决于几个方面。

无论如何,为了回答你的问题,我唯一能做的就是为你提供一个与你相似的具体案例。

代码很简单:

#include <string>

int main(int argc, char *argv[]) {
  std::string str = "this_is_a_string";
  int size = str.size();
  for (int i = 0; i < size; ++i) {
    str += std::to_string(i);
  }
  return 0;
}

结果汇编代码是(针对不同的优化级别):

GCC 6.2 -O0

 movl   $0x0,-0x14(%rbp)    // int i = 0;
 mov    -0x14(%rbp),%eax    // load i into the register
 cmp    -0x18(%rbp),%eax    // load size and compare with i in the register
 jge    401317 <main+0x91>  // jump if >=

GCC 6.2 -O1

 // initialization up
 add    $0x1,%ebx         // ++i (now i is stored in register)
 cmp    %ebx,-0x5c(%ebp)  // compare i and size (which is load from memory)
 je     0x80488a3 <main(int, char**)+136>  // jump if = (and not >=)

GCC 6.2 -O2

相同-O1

Here使用过的代码和程序集。

答案 3 :(得分:0)

是的,至少GCC和大多数其他编译器都会这样做。如果您尝试查看for循环变量是什么,那么当您使用-O1或更高版本进行编译时,调试器会说该变量已经过优化。当然,编译器不需要这样做。这就是标准所说的。

for语句

for ( for-init-statement conditionopt; expressionopt) statement

相当于

{
for-init-statement
    while ( condition ) {
    statement
    expression ;
    }
}