gcc如何优化此循环?

时间:2018-10-16 16:09:09

标签: c++ gcc g++ compiler-optimization undefined-behavior

所以我遇到了一些奇怪的行为,我将其简化为以下最小示例:

#include <iostream>
#include <vector>

int main()
{
  std::vector<int> vec;

  for(int i = 0; i < 1000; i++)
  {
    vec.push_back(2150000 * i);
    if(i % 100 == 0) std::cout << i << std::endl;
  }
}

使用命令使用gcc 7.3.0编译时

c++ -Wall -O2 program.cpp -o program

我没有任何警告。运行该程序将产生以下输出:

0
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300

[ snip several thousand lines of output ]

1073741600
1073741700
1073741800
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

我猜这意味着我终于为该向量耗尽了内存。

很显然,这里有问题。我猜这与2150000 * 1000略大于2 ^ 31有关,但这并不是那么简单-如果我将此数字减小为2149000,则程序将按预期运行:

0
100
200
300
400
500
600
700
800
900

cout对于重现此行为不是必需的,因此我认为实际上是一个最小的例子

#include <vector>

int main()
{
  std::vector<int> vec;

  for(int i = 0; i < 1000; i++)
  {
    vec.push_back(2150000 * i);
  }
}

运行此命令会使程序等待很长时间,然后崩溃。

问题

无论从哪方面来讲,我对C ++都是陌生的。我是否在做一些愚蠢的事情,允许出现未定义的行为?还是这是gcc中的错误?

我确实尝试过使用Google,但是我真的不知道该怎么做。

附录

我看到(带符号的)整数溢出是C ++中的未定义行为。据我了解,这仅表示表达式的行为

21500000 * i

是不确定的-即它可以求值为任意数字。也就是说,我们可以看到该表达式至少没有改变i的值。

1 个答案:

答案 0 :(得分:5)

要回答我自己的问题,在检查了汇编程序输出后,看起来g ++通过更改

优化了该循环。
for(int i = 0; i < 1000; i++)
{
  vec.push_back(2150000 * i);
}

类似

for(int j = 0; j < 1000 * 2150000; j += 2150000)
{
  vec.push_back(j);
}

我想加法要比每个周期进行乘法快,并且关于溢出是未定义行为的规则意味着可以进行此更改,而不必担心计算溢出时是否会引入意外行为。

当然,优化循环中的条件总是失败,所以最终我最终得到了类似的东西

for(int j = 0; true; j += 2150000)
{
  vec.push_back(j);
}