发生整数溢出时无符号整数和有符号整数的行为差异
Difference in behaviour of unsigned and signed integer when integer overflow occurs
阅读维基百科上关于整数溢出的文章
我不太明白为什么有符号整数的溢出会导致未定义行为,而无符号整数的溢出会导致环绕。为什么他们的行为会有所不同?
另一个问题:编程语言一般都有防止整数溢出的保护措施吗?差异的主要原因是C和c++语言规范允许实现使用以下三种不同的有符号整数表示之一
- 1的补充 <
- 2的补/gh>签署的
如果语言规范在有符号溢出的情况下规定了一些特定的行为(即优先考虑上述两种表示中的一种),它将迫使基于两种不受欢迎的表示的平台实现"重"有符号整数算术。这将是必要的,因为这些平台的自然机器级行为与语言标准所要求的行为不匹配。这些实现必须不断地监视有符号溢出,并调整结果以满足标准需求。
这将严重降低使用不受欢迎的符号表示的平台上的有符号整数算术的性能,当然,这在C和c++这样的语言中是完全不可接受的,当涉及到像整数算术这样的基本操作时,这些语言被设计成尽可能接近底层硬件。
行为是undefined(与*unspecified"相反)的原因是因为在整数运算期间有符号溢出的情况下,有些平台故意生成硬件异常。注意,该行为仅对通常由机器执行的算术运算没有定义。对于值转换,有符号溢出不会产生未定义的行为(该行为实际上是由实现定义的)。
对于无符号类型,它们在所有平台上的表示都是相同的,这意味着要求在所有平台上保持一致的行为不是问题。在概念上符合"模2^width"行为的封装是几乎所有已知二进制硬件平台上的自然行为。
因为语言就是这样定义的。它允许在更多种类的硬件上更容易地开发符合标准的实现(例如,具有饱和算法的dsp)。
取决于语言。一些硬件可以,你可以在你的程序中利用它。
C/c++处理整数溢出的方法是提供在你正在工作的机器上最快的行为,所以在某些机器上(这里假设16位有符号整数):
32766 + 2 == -32768
,但在某些机器上是:
32766 + 2 == 32767
对于其他机器,您可以设置trap值或任何CPU将执行的操作。
注意Java有完美定义的整数溢出,以实现"一次写入,到处运行"。
对于无符号整数——它们的大部分应用是位掩码、位域和数字操作(模操作、标识符)——正是你不想让它们未定义的操作。
有些编程语言有这样的安全措施,有些没有:
Python 3自动将溢出的值转换为long类型(任意大的整数)。
在C/c++中,你必须自己检查溢出条件,climits (C)和limits (c++)头已经为每种类型定义了最大值和最小值。
在x86汇编中编程-在FLAGS和EFLAGS寄存器中有CF(进位标志)和OF(溢出标志)来检查何时发生溢出
许多语言也有任意精度类型,以防您想避免溢出,但操作速度较慢,因为这些变量(理论上)可能和您的内存一样大。
在Java中,您只有无符号的int
和long
值,并且无论您运行它,它们的行为都是一致的。如果你给整数加1。MAX_VALUE你打赌的整数。MIN_VALUE(换行),如果从Long中减去1。MIN_VALUE你得到Long.MAX_VALUE
所以我不知道为什么unsigned值的行为在其他语言中是未定义的。
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 检查TCHAR数组输入是否为带符号整数C++
- 如何打印boost多精度128位无符号整数
- C++模板函数,用于比较任何无符号整数和有符号整数
- 在数字之间插入 + 或 - 符号以使其等于整数
- 为什么:不同符号的整数比较只是偶尔发生?
- 将超出范围的整数分配给有符号字符类型
- 为什么乘以常量有符号整数分数没有优化?
- 如何解决隐式转换丢失整数精度:'size_t'(又名"无符号长")到'int'警告?
- 在线程中读取无符号整数时,c++ 位是否以原子方式切换?
- FlatBuffers/Protobuf 中是否有支持任意 24 位有符号整数定义的可移植二进制序列化架构?
- C++11 标准是否保证零值有符号整数的一元减号为零?
- 整数类型应该显式转换(例如"int"到"无符号")还是只会增加混乱?
- Constexpr 可变参数模板,用于对无符号整数进行重新排序
- AVX2 整数乘以有符号 8 位元素,产生有符号 16 位结果?
- 为什么 Clang 和 GCC 中两个无符号整数之和的结果类型不同
- 使用192/256位整数求和无符号64位整数向量的点积的最快方法
- 为什么对无符号字符进行算术运算会将它们提升为有符号整数
- 从 std::string 转换为 const 无符号整数
- 矢量浮点到整数/符号转换