我在 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/