我编写了这段 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++
将导致整数溢出,从而导致未定义的行为。
可能 Sum
或 Result
也会先于 i
溢出。
当保证程序触发未定义行为时,程序的整个行为都是未定义的。
gcc 以积极优化触发 UB 的路径而闻名。您可以检查汇编代码以查看您的情况到底发生了什么。也许 -O2
和更高的情况删除了循环结束条件检查,但 -O1
将其保留在那里并“依赖” INT_MAX + 1
导致 INT_MIN
。
关于c - 为什么 GCC -O2 和 -O3 优化会破坏这个程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32824534/