22

我只是想知道整数溢出到底有多可怕。以下面的示例程序为例:

#include <iostream>

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

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


我根据以下标准引号从我的问题中删除了“签名”部分:

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

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

4

3 回答 3

21

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

最好的例子是:Why does integer overflow on x86 with GCC cause an infinite loop?

在 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 会优化循环测试并使其成为无限循环。

于 2012-01-26T20:47:53.817 回答
8

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

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

于 2012-01-26T20:28:27.523 回答
5

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

虽然可能已经引入了关于溢出的 UB,以考虑到在溢出时捕获或饱和的硬件以及表示之间的结果差异,因此在这种情况下可以为第一种观点争论,但编写优化器的人非常认为如果标准不能保证某些事情,那么任何事情都可能发生,他们会尝试利用每一个自由来生成运行得更快的机器代码,即使结果不再有意义。

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

于 2012-01-26T21:05:45.987 回答