为什么GCC -O2和-O3优化会中断该程序?

Boj*_*V03 4 c optimization gcc integer-overflow infinite-loop

我已经编写了此C代码,用于查找等于其数字的阶乘之和的所有整数的总和。在没有任何GCC优化标志的情况下完成该工作大约需要一分钟,使用-O1可以将时间减少约15-20秒,但是当我尝试使用-O2,-O3或-Os时,它陷入了无限循环。

int main()
{
  int i, j, factorials[10];
  int Result=0;

  for(i=0; i<10; i++)
  {
    factorials[i]=1;
    for(j=i; j>0; j--)
    {
      factorials[i] *= j;
    }
  }

  for(i=3; i>2; i++) //This is the loop the program gets stuck on
  {
    int Sum=0, number=i;

    while(number)
    {
      Sum += factorials[number % 10];
      number /= 10;
    }

    if(Sum == i)
      Result += Sum;
  }

  printf("%d\n", Result);  
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我已查明这for(i=3; i>2; i++)是问题的原因。所以很明显i永远不会小于2?

这与整数溢出行为未定义有关吗?如果是这样,那么有关这些情况下程序究竟发生了什么的更多信息?

编辑:我想我应该提到,我知道其他编写for循环的方法,这样它就不会使用溢出(我希望INT_MAX + 1等于<2的INT_MIN),但这是只是做一个随机测试以查看会发生什么,所以我在这里张贴了它以了解到底发生了什么:)

M.M*_*M.M 5

循环是for (i = 3; i > 2; i++),它没有break语句或其他退出条件。

最终i会达到INT_MAX然后i++整数将导致整数溢出,从而导致不确定的行为。

可能SumResult之前也会溢出i

当保证某个程序会触发未定义的行为时,该程序的整个行为都是未定义的。

gcc因积极优化触发UB的路径而闻名。您可以检查汇编代码以查看实际情况。也许-O2和更高的情况下,除去循环结束条件检查,但-O1把它放在那里的“依赖” INT_MAX + 1导致INT_MIN