4

在维基百科上阅读这篇关于整数溢出的文章

我不太明白为什么有符号整数的溢出会导致未定义的行为,但无符号整数的溢出会导致环绕。为什么它们的行为会有所不同?

另一个问题:编程语言一般有防止整数溢出的保护措施吗?

4

4 回答 4

2

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

  1. 1 的补码
  2. 2 的补码
  3. 有符号的幅度

如果语言规范在有符号溢出的情况下要求某些特定行为(即,在其他两种情况下更倾向于上述表示之一),它将强制基于两种非优先表示的平台实现“重”有符号整数运算。这将变得有必要,因为此类平台的自然机器级行为与语言标准所要求的行为不匹配。这些实现必须不断观察签名溢出并调整结果以符合标准要求。

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

行为未定义(与“未指定”相反)的原因是,有些平台会在整数运算过程中出现有符号溢出时故意生成硬件异常。请注意,该行为仅适用于算术运算,通常是由机器执行。对于值转换,有符号溢出不会产生未定义的行为(该行为实际上是实现定义的)。

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

于 2012-12-21T17:28:34.827 回答
1
  1. 因为这就是语言的定义方式。它允许在更多种类的硬件上更容易地开发符合要求的实现(例如,具有饱和算法的 DSP)。

  2. 取决于语言。某些硬件可以,您也许可以在您的程序中利用它。

于 2012-12-21T15:46:01.050 回答
1

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

32766 + 2 == -32768

但在某些机器上是:

32766 + 2 == 32767

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

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

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

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

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

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

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

许多语言还具有任意精度类型,以防您想避免溢出,但操作速度较慢,因为此类变量(理论上)可以与您的内存一样大。

于 2012-12-21T17:20:05.403 回答
0

在 Java 中,您只有 unsignedintlong值,并且无论您在何处运行,它们的行为都是一致的。如果你在 Integer.MAX_VALUE 上加 1,你赌 Integer.MIN_VALUE(它会换行),如果你从 Long.MIN_VALUE 中减去 1,你会得到 Long.MAX_VALUE。

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

于 2012-12-21T15:55:03.163 回答