c - 为什么 GCC -O2 和 -O3 优化会破坏这个程序?

标签 c gcc optimization infinite-loop integer-overflow

我编写了这段 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;
}

我已经确定 for(i=3; i>2; i++) 是问题的原因。那么显然 i 永远不会小于 2?

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

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

最佳答案

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

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

可能 SumResult 也会先于 i 溢出。

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

gcc 以积极优化触发 UB 的路径而闻名。您可以检查汇编代码以查看您的情况到底发生了什么。也许 -O2 和更高的情况删除了循环结束条件检查,但 -O1 将其保留在那里并“依赖” INT_MAX + 1导致 INT_MIN

关于c - 为什么 GCC -O2 和 -O3 优化会破坏这个程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32824534/

相关文章:

c - 没有库如何生成笔记?

c - 十六进制参数 "or"| C 中的运算符

performance - 使两个直方图成比例的算法,最小化了删除的单位

c++ - 编译器是否足够聪明,可以优化具有与静态方法参数相同的成员的仿函数?

c - 将 CSV 字符串导入到 C 中的多维数组中

c++ - OpenCL 或 CUDA 走哪条路?

c - 如何初始化 const float32x4x4_t (ARM NEON intrinsic, GCC)?

c++ - 使用gcc编译c/c++程序

c++ - 在 AT&T 内联汇编中将 float / double 设置为常量值

mysql - 将大表拆分为单独的表,并在需要时进行 MySql Union 选择