相关疑难解决方法(0)

为什么带有GCC的x86上的整数溢出会导致无限循环?

以下代码进入GCC的无限循环:

#include <iostream>
using namespace std;

int main(){
    int i = 0x10000000;

    int c = 0;
    do{
        c++;
        i += i;
        cout << i << endl;
    }while (i > 0);

    cout << c << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

所以这是交易:有符号整数溢出在技术上是未定义的行为.但是x86上的GCC使用x86整数指令实现整数运算 - 它包含溢出.

因此,我本来期望它包装溢出 - 尽管事实上它是未定义的行为.但事实显然并非如此.那么我错过了什么?

我使用以下方法编译:

~/Desktop$ g++ main.cpp -O2
Run Code Online (Sandbox Code Playgroud)

GCC输出:

~/Desktop$ ./a.out
536870912
1073741824
-2147483648
0
0
0

... (infinite loop)
Run Code Online (Sandbox Code Playgroud)

禁用优化后,没有无限循环且输出正确.Visual Studio也正确编译它并给出以下结果:

正确的输出:

~/Desktop$ g++ main.cpp
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
3
Run Code Online (Sandbox Code Playgroud)

以下是一些其他变体:

i *= 2;   //  Also …
Run Code Online (Sandbox Code Playgroud)

c c++ x86 gcc undefined-behavior

124
推荐指数
5
解决办法
1万
查看次数

整数文字的类型默认不是int?

我刚刚回答了这个问题,它问为什么迭代直到for循环中的100亿需要更长时间(OP实际上在10分钟后中止)比迭代直到10亿:

for (i = 0; i < 10000000000; i++)
Run Code Online (Sandbox Code Playgroud)

现在我和其他许多人明显的答案是,这是因为迭代变量是32位(从未达到100亿)并且循环得到无限循环.

但是虽然我意识到了这个问题,但我仍然想知道编译器内部究竟发生了什么?

由于文字没有附加一个L,它应该是IMHO类型int,因此32位.因此,由于溢出,它应该是int范围内的正常可达.为了真正认识到无法从中获取int,编译器需要知道它是100亿,因此将其视为超过32位的常量.

这样的文字是否会自动升级到拟合(或至少是实现定义的)范围(在这种情况下至少是64位),即使没有附加L并且是这个标准行为?或者是在幕后发生了什么不同,比如UB由于溢出(整数溢出实际上是UB)?标准中的一些引用可能很好,如果有的话.

虽然最初的问题是C,但我也很欣赏C++的答案,如果有的话.

c c++ overflow literals

32
推荐指数
2
解决办法
1万
查看次数

标签 统计

c ×2

c++ ×2

gcc ×1

literals ×1

overflow ×1

undefined-behavior ×1

x86 ×1