为什么默认情况下不会检查溢出

时间:2016-12-13 09:33:21

标签: java c integer-overflow

我发现了一些关于在执行上溢/下溢行为之前检查操作的问题。似乎有很多方法可以很容易地做到这一点。那么为什么没有选项可以在执行前自动检查每个数学运算,或者为什么没有缓冲算术运算上溢/下溢的异常?或者用不同的方式表达:在什么情况下允许操作不被注意地溢出是有用的?

这可能是运行时的问题吗?或者是在非数学运算期间发生溢出的主要来源?

3 个答案:

答案 0 :(得分:3)

实际上,对于C,有检查选项,请参见此处:http://danluu.com/integer-overflow/

至于java,添加整数溢出检查会打开一堆蠕虫。由于java不提供无符号类型,因此无符号数学通常以普通int或long类型完成 - 显然VM不会神奇地意识到操作的无符号性质,这意味着您需要添加无符号类型或程序员需要要非常注意打开/关闭支票。可以在Arrays.binarySearch中找到带有签名类型的无符号数学的示例。另外,Java确实定义了溢出情况下的结果,因此依赖于溢出行为是对已定义行为的合法使用。

正如上面C链接中简要分析的那样,由于粗略实施和/或干扰其他代码优化,这些检查在实践中会对性能产生严重影响。

此外,虽然大多数CPU可以检测到溢出(通常通过C和V标志),但它们同时执行签名/无符号(常见的CPU ISA不会在签名/未签名之间产生干扰)在add / sub的情况下的操作。由程序来响应这些标志,这意味着在代码中插入附加指令。同样,这意味着程序员/编译器必须知道该操作是打算签名还是未签名才能做出正确的选择。

因此溢出检测确实带来了成本,尽管可以通过良好的编译器支持使其变得相当小。

但是在很多情况下,溢出要么不可能通过设计(例如函数的有效输入参数不能产生溢出),所需(例如环绕行为计数器),或者当它们确实发生时会被其他方法捕获使用(例如通过数组边界检查)。

我必须认真思考实际上我觉得需要进行溢出检查的情况。通常,您更关心的是验证特定点的值范围(例如函数参数)。但这些是函数特定值范围的任意检查,编译器甚至无法知道(好吧,在某些语言中它会,因为它明确表达,但Java和C都不属于这一类)。

所以溢出检查并不普遍有用。它并不意味着它没有任何可能阻止的潜在错误,但与其他错误类型相比,溢出并不是一个常见的问题。我不记得上次看到整数溢出导致的错误。例如,关闭一个错误就更常见了。另一方面,有一些微观优化显然依赖于溢出环绕(例如我的一个老问题,请参见接受的答案:Performance: float to int cast and clipping result to range)。

根据所描述的情况,强制C / Java检查并响应整数溢出将使它们更糟糕的语言。它们会更慢,和/或程序员只是停用该功能,因为它阻碍了它的使用。这并不意味着溢出检查,因为语言功能通常会很糟糕;但要真正从中获取一些东西,环境也需要适合(例如,如上所述,Java需要无符号类型)。

TL; DR它可能很有用,但它需要更深入的语言支持,而不仅仅是一个有用的开关。

答案 1 :(得分:1)

Java语言没有内置此功能作为直接应用于+-*运算符的关键字或机制。例如,C#包含checkedunchecked个关键字。但是,当语言中没有本机支持时,这些检查可能昂贵并且难以实现。至于Java 1.8,方法addExactsubtractExactmultiplyExact已添加到API中以提供此功能,正如@Tom在评论中所指出的那样。

为什么即使语言支持,也不会自动 ?简单的答案是,一般来说,过度和下溢都可以被接受或想要的行为,或者它们根本就不会发生,因为它应该是的复杂且执行良好的设计。我会说,利用上溢和下溢是一种低级或无害的编程问题,以避免出于性能原因而进行额外操作。

总的来说,您的应用程序设计应明确说明明智使用算术上溢和下溢,或者根本不需要使用它们,因为它可能导致混淆,不直观的行为或严重的错误。在第一种情况下,您不检查,在第二种情况下,检查将是无用的。自动检查将是超级飞行,只是性价比。

一个想要溢出的人为例子可能是一个反击。假设您有一张未签名的短片并将其计算在内。在65536之后,由于溢出,它会回到零,这很方便。

答案 2 :(得分:1)

我可以提供两个潜在因素,为什么未选中的算术是默认值:

  • 熟悉感:默认情况下,未选中C和C ++中的算术,熟悉这些语言的人不会指望程序抛出,而是默默地继续。这是一种误解,因为C和C ++在有符号整数溢出/下溢上都有未定义的行为。但是,它在许多人的思想中产生了一定的期望,同一家庭中的新语言往往会回避明显违反既定惯例。
  • 基准性能:检测上溢/下溢通常需要执行比您决定忽略它时所需的更多指令。想象一下,如果一个不熟悉它的人写了一个数学密集的基准(经常发生)并且"证明了#34;即使对于最简单的数学运算,语言也比C和C ++慢得多。这会损害人们对语言表现的看法,并可能妨碍其采用。