【问题标题】:Arith Overflows in java: why there are no exceptions at run time and no compiler warnings?java中的Arith溢出:为什么在运行时没有异常并且没有编译器警告?
【发布时间】:2012-02-19 10:45:39
【问题描述】:

我知道这个问题已经部分回答了here on S.O.,但他们在那里解释了算术溢出期间发生的情况。以及 S.O. 的其他地方。他们用java代码解释how to check for overflow,即防止它作为程序员。

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

AFAIK,以前没有人回答过这个问题。

在 Bruce Eckel 的书中Thinking in Java,第 1 版。 (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”时没有变化

我已经在从 1.2 到 1.6 的一些 java 编译器上尝试过这个,它仍然显示这种行为。我现在想知道为什么会这样?

  • 这是错误还是功能?
  • 这是无法检测到的,还是编译器设计人员的低优先级问题?
  • 由于向后兼容性,这不是固定的吗?
  • 也许在较新版本的 JDK 中,是否可以通过启用一些很少使用的编译器开关/-D:property 或一些 java VM 参数 (-XX:...) 在编译时进行控制?

刚才我用的是这些虚拟机,Windows x86 32 bit

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

【问题讨论】:

标签: c# java overflow compiler-warnings


【解决方案1】:

语言规范要求溢出计算的环绕行为,所以它是一个特性。由于在编译时无法检测到大多数溢出,因此检查可以检测到的溢出的价值值得怀疑,特别是因为它们可能是故意的。

【讨论】:

  • 也许它对科学计算领域仍有一些价值?有人可能会添加这样一个可选警告,例如,作为“迂腐”级别的编译警告的一部分。
  • 有些价值,是的,但有限。编译器无论如何都找不到所有可能溢出的地方,所以即使没有警告的编译仍然需要你检查你的代码,如果你不能有溢出。因此,如果避免溢出很重要,您必须检查自己或使用不会溢出/触发异常的类型 - BigInteger 可以处理您通常需要的所有内容以及更多内容,我认为会引发异常当它溢出时(我知道 GMP 类型在尝试分配太大的值时调用 abort())。
【解决方案2】:

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

内置的整数运算符不会以任何方式指示上溢或下溢。

此外,几乎所有语言都会通过使用环绕溢出而不是引发溢出错误来表现这种行为。为什么?部分原因是历史上一直是这样,而且如果您将整数算术视为纯二元运算会更容易。

【讨论】:

  • +1 获取规范的链接。关于“几乎所有语言都会这样表现”​​,值得指出两个重要的例子,C 和 C++,其中 signed 整数的溢出是未定义的行为,所以你不能指望它们以这种方式行事(有时他们不会这样做;但是,gcc 有一个 -fwrapv 标志来强制这种行为)。不过,无符号整数需要使用包装/取模行为。
【解决方案3】:

这可能是由于performance concerns

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 2010-10-14
    相关资源
    最近更新 更多