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

How disastrous is integer overflow in C++?

本文关键字:灾难性 溢出 整数 C++      更新时间:2023-10-16

我只是想知道整数溢出到底有多灾难

#include <iostream>
int main()
{
    int a = 46341;
    int b = a * a;
    std::cout << "hello worldn";
}

由于a * a在32位平台上溢出,整数溢出会触发未定义的行为,我有任何保证hello world会真正出现在我的屏幕上吗?


我删除了";签名的";我的问题的一部分基于以下标准报价:

(§5/5 C++03,§5/4 C++11)如果在评估表达式的过程中,结果没有在数学上定义,或者不在其类型的可表示值范围内,则行为是未定义的。

(§3.9.1/4)声明为unsigned的无符号整数应遵守算术模2^n定律,其中n是该特定大小整数的值表示中的位数。这意味着无符号算术不会溢出,因为无法由结果的无符号整数类型表示的结果会以比结果的无签名整数类型所能表示的最大值大一的数字为模进行减少。

正如@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;
}

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

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

编辑:注意,gcc有-ftrapv选项(但它似乎对我不起作用)。

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

虽然引入关于溢出的UB可能是为了考虑在溢出时捕获或饱和的硬件以及表示之间的结果差异,因此在这种情况下,人们可以支持第一种观点,但编写优化器的人非常坚信,如果标准不能保证什么,实际上,任何事情都可能发生,他们试图利用每一块自由来生成运行速度更快的机器代码,即使结果不再有意义。

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