发生整数溢出时无符号和有符号整数的行为差异

时间:2012-12-21 15:43:50

标签: java c++ c programming-languages

在维基百科上阅读有关Integer Overflow

的文章

我不太清楚为什么溢出有符号整数会导致未定义的行为,但无符号整数的溢出会导致包围。为什么它们的行为会有差异?

另一个问题:编程语言通常是否有针对整数溢出的保护措施?

4 个答案:

答案 0 :(得分:2)

差异的主要原因是C和C ++语言规范允许实现使用以下三种不同的有符号整数表示之一

  1. 1的补充
  2. 2的补充
  3. 签名幅度
  4. 如果语言规范在签名溢出的情况下强制要求某些特定行为(即上述表示优于其他两个表示),它将强制基于两个非优选表示的平台实现“重”有符号整数算法。这将是必要的,因为这种平台的自然机器级行为与语言标准所要求的行为不匹配。这些实现必须不断监视签名溢出并调整结果以符合标准要求。

    这会严重降低使用非优惠签名表示的平台上的有符号整数运算的性能,当然,这在C和C ++这样的语言中是完全不可接受的,这些语言的设计尽可能接近于当涉及整数算术等基本操作时的底层硬件。

    行为未定义(与*未指定相反)的原因是因为存在那些在整数算术期间出现符号溢出时故意生成硬件异常的平台。注意,行为对于通常由机器执行的算术运算是未定义的。对于值转换,签名溢出不会产生未定义的行为(行为实际上是实现定义的)。

    对于无符号类型,它们在所有平台上的表示相同,这意味着要求跨所有平台的一致行为不是问题。概念上匹配“modulo 2 ^ width”行为的环绕声是几乎所有已知二进制硬件平台上的自然行为。

答案 1 :(得分:1)

  1. 因为这是定义语言的方式。它允许在更多种类的硬件上(例如,具有饱和算术的DSP)更容易地开发符合要求的实现。

  2. 取决于语言。一些硬件可以,并且您可以在程序中利用它。

答案 2 :(得分:1)

整数溢出的C / C ++方法是提供在你正在处理的机器上最快的行为,所以在某些机器上(这里假设16位有符号整数):

32766 + 2 == -32768

但在某些机器上是:

32766 + 2 == 32767

对于其他机器,您可以拥有陷阱值或CPU将执行的任何操作。

注意Java完全定义了整数溢出,实现“一次编写,随处运行”。

对于无符号整数 - 它们的大多数应用程序都是位掩码,位域和数字操作(模运算,标识符) - 正是你没有定义它们的操作。

有些编程语言有这样的安全措施,有些则没有:

  • Python 3自动转换溢出的值为long(任意大整数)的值。

  • 在C / C ++中,您必须自己检查溢出条件,climbits(C)和限制(C ++)标头已为每种类型定义了最大值和最小值。

  • 在x86程序集中编程 - 有无符号的CF(进位标志)和OF(溢出标志),用于签名FLAGS和EFLAGS寄存器以检查何时发生溢出。

许多语言也有任意精度类型,如果你想避免溢出,但操作较慢,因为这些变量(理论上)可以和你的记忆一样大。

答案 3 :(得分:0)

在Java中,您只有未签名的intlong值,并且无论您在何处运行它们,它们的行为都是一致的。如果你将Integer.MAX_VALUE加1,你输入Integer.MIN_VALUE(它换行),如果你从Long.MIN_VALUE中减去1,你得到Long.MAX_VALUE。

所以我不知道为什么在其他语言中未定义无符号值的行为。