我只是想知道灾难性的整数溢出是多少。参加以下示例程序:
#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是该特定整数大小的值表示中的位数。这意味着无符号算术不会溢出,因为无法用结果无符号整数类型表示的结果以比模式生成的无符号整数可表示的最大值的数量为模的方式减少。类型。
答案 0 :(得分:21)
正如@Xeo在评论中指出的那样(我实际上是先在C++ chat提出来的):
未定义的行为确实意味着它,它可以在你最不期望的时候打动你。
最好的例子是: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优化了循环测试并使其成为无限循环。
答案 1 :(得分:8)
您可以触发某些硬件安全功能。所以不,你没有任何保证。
编辑:
请注意,gcc具有-ftrapv
选项(但它似乎对我不起作用)。
答案 2 :(得分:5)
有两种关于未定义行为的观点。有一种观点是它可以收集奇怪的硬件和其他特殊情况,但通常它应该表现得很好。并且有观点认为任何事情都可能发生。根据UB的来源,有些人持有不同的意见。
虽然可能已经引入了关于溢出的UB,考虑到溢出时陷阱或饱和的硬件以及表示之间的结果差异,因此人们可以争论第一种观点,在这种情况下,编写优化器的人非常珍惜认为如果标准不能保证某些东西,那么任何事情都会发生,并且他们试图利用每一件自由来生成运行速度更快的机器代码,即使结果不再有意义。< / p>
因此,当您看到未定义的行为时,假设任何事情都可能发生,但无论合理的行为是多么合理。