2012-02-19 88 views
4

我知道这个问题已经部分回答了here on S.O.,但他们解释了什么发生在算术溢出。在S.O.的其他地方。他们在java代码中解释how to check for overflow,即阻止它作为程序员。java中的Arith溢出:为什么在运行时没有异常并且没有编译器警告?

在这里,我问为什么有在运行时没有异常,没有编译器警告

AFAIK,这个还没有回答过。

在Bruce Eckel的书Thinking in Java,1st ed。 (2000年),第3章,还有这个小Java程序:

//: Overflow.java 
// Surprise! Java lets you overflow. 
public class Overflow { 
     public static void main(String[] args) { 
     int big = 0x7fffffff; // max int value 
     prt("big = " + big); 
     int bigger = big * 4; 
     prt("bigger = " + bigger); 
     } 
     static void prt(String s) { 
     System.out.println(s); 
     } 
} ///:~ 

的这个输出是:

big = 2147483647 
bigger = -4 

,你会得到任何错误或编译器警告,并没有异常运行时为 。

没有当Integer.MAX_VALUE的是用来代替“0x7FFFFFFF的”

我曾经尝试这样做了一些Java编译从1.2到1.6,它仍然显示这种行为的改变。我现在想知道为什么这样?

  • 这是一个错误?
  • 这是不可能检测到的,或者是编译器设计者的一个低优先级问题?
  • 由于向后兼容,这是不是固定的?
  • 也许在JDK的新版本中,可以在编译时通过启用一些很少使用的编译器开关/ -D:属性或一些Java VM参数(-XX:...)来控制它吗?

刚才我用这些虚拟机时,Windows x86的32位

Java(TM) SE Runtime Environment (build 1.6.0_22-b04) 
Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing) 

Java(TM) SE Runtime Environment (build 1.7.0_03-b05) 
Java HotSpot(TM) Client VM (build 22.1-b02, mixed mode, sharing) 


顺便说一句,C#(Microsoft.CSharp \ v4.0_4.0.0。 0)显示相同的行为

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace OverflowCheck 
{ 
    class Overflow 
    { 
     static void Main(string[] args) 
     { 
      int big = 0x7fffffff; // same behaviour vor Int32.MaxValue 
      prt("big = " + big); 
      int bigger = big * 4; 
      prt("bigger = " + bigger); 
      prt("done"); 
     } 
      static void prt(String s) { 
      System.Console.WriteLine(s); 

     } 
    } 
} 

输出:

big = 2147483647 
bigger = -4 
+0

在C#中,行为是可配置的,包括通过'checked'关键字:请参阅http://msdn.microsoft.com/en-us/library/74b4xzyw(v=vs.71).aspx – 2012-02-19 12:26:30

回答

4

语言规范强制执行溢出计算的环绕行为,所以它是一个功能。由于大多数溢出在编译时不能被检测到,所以检查那些可被检测到的值是可疑的,特别是因为它们可能是有意的。

+0

也许它可能仍然对科学计算领域有一定的价值吗?有人可能会添加这样的可选警告,例如,编辑警告的“迂腐”级别的一部分。 – knb 2012-02-19 11:10:39

+0

有些价值,是的,但有限。编译器无论如何都无法找到可能溢出的所有地方,所以即使没有警告的编译仍然需要您检查代码是否不能溢出。因此,如果避免溢出非常重要,则必须检查自己或使用不会溢出/触发异常的类型 - “BigInteger”可以处理您通常需要的一切以及一些超出的内容,并且我认为会引发异常当它溢出时(我知道GMP类型在尝试分配太大的值时调用'abort()')。 – 2012-02-19 11:26:50

1

这可能是由于performance concerns

对于大量数据,验证数字范围的正确性可能会导致显着的减速。

2

这在Java语言规范规定:http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.2

内置整数运算符不表明以任何方式溢或下溢。

此外,几乎所有语言都会通过使用环绕溢出而不是抛出溢出错误的方式来表现这种方式。为什么?部分原因在于它一直是这种方式,并且因为如果将整数算术看作纯粹的二元运算,则更容易。

+0

谢谢,只能接受一个答案。 – knb 2012-02-19 11:03:52

+1

+1链接到规范。关于“几乎所有的语言都会这样做”,值得指出两个重要的例子,C和C++,其中_signed_整数的溢出是未定义的行为,所以你不能指望它们的行为(有时他们不要;但gcc有一个'-fwrapv'标志强制这种行为,但是)。不过,无符号整数需要使用包装/模数行为。 – 2012-02-19 11:16:18

相关问题