java - 为什么默认不检查溢出

标签 java c integer-overflow

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

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

最佳答案

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

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

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

此外,虽然大多数 CPU 可以检测到溢出(通常通过 C 和 V 标志),但它们同时检测有符号/无符号(普通 CPU ISA 在加/减时不区分有符号/无符号操作) .由程序来响应这些标志,这意味着在代码中插入额外的指令。同样,这意味着程序员/编译器必须知道操作是有符号的还是无符号的,以便做出正确的选择。

所以溢出检测确实是有代价的,尽管它可以通过良好的编译器支持变得相当小。

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

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

所以溢出检查并不是普遍有用的。这并不意味着没有任何它可以防止的潜在错误,但与其他错误类型相比,溢出并不是一个真正常见的问题。我不记得上次看到整数溢出导致的错误是什么时候了。例如,差一个错误要普遍得多。另一方面,有一些显式依赖溢出环绕的微优化(例如我的一个老问题,请参阅已接受的答案:Performance: float to int cast and clipping result to range)。

对于所描述的情况,强制 C/Java 检查和响应整数溢出会使它们成为更糟糕的语言。它们会更慢,和/或程序员会简单地停用该功能,因为它比它有用的多。这并不意味着溢出检查作为一种语言特性通常是不好的;但要真正从中获益,环境也需要适应(例如,如上所述,Java 需要无符号类型)。

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

关于java - 为什么默认不检查溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41117633/

相关文章:

java - 我的代码中的任何更改是否会导致客户端代码出现问题?

java - 用于 JavaFX Scene Builder 拖放的 IntelliJ IDEA 插件停止工作

java - 当邮政编码以 0 开头或以 0 结尾时,程序无法运行

c - 执行命令和打印输出的函数

检查命令行输入是否为数字

c++ - "Int"c++ 与 "long long"结果的乘法

c++ - 大数相乘产生错误的值

javascript - 如果 Date.now() 大于 Number.MAX_SAFE_INTEGER 会发生什么?

java - 随机选择字符串后如何从数组中删除字符串? java

c - 在 C 中使用多线程的矩阵乘法