C++中的整数溢出是多么灾难性
How disastrous is integer overflow in C++?
我只是想知道整数溢出到底有多灾难
#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可能是为了考虑在溢出时捕获或饱和的硬件以及表示之间的结果差异,因此在这种情况下,人们可以支持第一种观点,但编写优化器的人非常坚信,如果标准不能保证什么,实际上,任何事情都可能发生,他们试图利用每一块自由来生成运行速度更快的机器代码,即使结果不再有意义。
因此,当你看到一个未定义的行为时,假设任何事情都可能发生,无论给定的行为看起来多么合理。
- 'short int'持有的值溢出,但"自动"不会溢出?
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 大于65535的C++数组[size]引发不一致的溢出
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- C++中无符号字符溢出
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 整数溢出,最大值为 pow(10,19)
- 获取隐式转换溢出从无符号到已签名的警告
- 使用 strcat 获取缓冲区溢出错误
- LeetCode 1:两和 - 地址清理器:堆缓冲区溢出地址
- 给定一个类型,如何派生一个泛型更广泛的类型(例如,用于溢出安全求和)?
- C++ 对象数组堆栈溢出
- 使用提升::lexical_cast捕获溢出
- C++ Unordered_set功能中的溢出
- 自定义排序函数中的堆溢出
- 使用向量的缓冲区溢出
- 有没有一种方法可以捕获进程中的堆栈溢出?C++Linux
- 如何修复此特征矩阵反演溢出错误?
- C++中的整数溢出是多么灾难性