C++中的整数溢出有多么灾难性?

fre*_*low 22 c++ integer-overflow undefined-behavior

我只是想知道灾难性的整数溢出是多么的真实.采用以下示例程序:

#include <iostream>

int main()
{
    int a = 46341;
    int b = a * a;
    std::cout << "hello world\n";
}
Run Code Online (Sandbox Code Playgroud)

由于a * a32位平台上的溢出和整数溢出触发了未定义的行为,我是否有任何hello world实际出现在屏幕上的保证?


我根据以下标准引文从我的问题中删除了"已签名"部分:

(§5/ 5 C++ 03,§5/ 4 C++ 11)如果在评估表达式期间,结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义.

(§3.9.1/ 4)声明的无符号整数unsigned应遵守算术模2 ^ n的定律,其中n是该特定整数大小的值表示中的位数.这意味着无符号算术不会溢出,因为无法由结果无符号整数类型表示的结果以比模式生成的无符号整数类型所表示的最大值大1的数量为模.

Mys*_*ial 21

正如@Xeo在评论中所指出的那样(我实际上是在C++聊天中首先提到的): 未定义的行为确实意味着它,它可以在你最不期望的时候打动
你.

最好的例子是:为什么带有GCC的x86上的整数溢出会导致无限循环?

在x86上,有符号整数溢出只是一个简单的环绕.通常情况下,你会期望在C或C++中发生同样的事情.但是,编译器可以进行干预 - 并使用未定义的行为作为优化的机会.

在从该问题中取得的示例中:

#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)

当使用GCC编译时,GCC优化了循环测试并使其成为无限循环.

  • 这种情况的另一个例子是 - > http://stackoverflow.com/questions/7124058/compiler-optimization-causing-program-to-run-slower (2认同)

Let*_*_Be 8

您可以触发一些硬件安全功能.所以不,你没有任何保证.

编辑:请注意,gcc有-ftrapv选项(但它似乎不适合我).

  • `-ftrapv`只有在为信号注册处理程序时才会执行任何操作.它本身不会导致崩溃或任何其他可观察的行为. (4认同)
  • 而不是`-ftrapv`你是否想到`-fwrapv`扩展来处理像无符号溢出一样的有符号溢出? (2认同)

APr*_*mer 5

关于未定义的行为有两种观点.有一种观点是它可以收集奇怪的硬件和其他特殊情况,但通常它应该表现得很清醒.并且有观点认为任何事情都可能发生.根据UB的来源,有些人持有不同的意见.

虽然可能已经引入了关于溢出的UB,考虑到溢出时陷阱或饱和的硬件以及表示之间的结果差异,因此人们可以争论这种情况下的第一个视图,编写优化器的人非常认真地看待如果标准不能保证某些东西,那么任何事情都会发生,并且他们试图利用每一件自由来生成运行速度更快的机器代码,即使结果不再有意义.

所以当你看到一个未定义的行为时,假设任何事情都可能发生,无论看起来多么合理.

  • 关于整数溢出是未定义的行为允许许多平台进行实质性的优化,否则这是不可能的.例如,如果整数x和y的唯一方法可能是负的,那么编译器可以使用无符号算术计算"x/y"(这可能意味着指令与函数调用之间的差异).太糟糕了,没有无符号类型,其中溢出将是UB,因为一些优化也将成为可能. (2认同)