为什么语言默认情况下不会在整数溢出上引发错误? [英] Why don't languages raise errors on integer overflow by default?

查看:92
本文介绍了为什么语言默认情况下不会在整数溢出上引发错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在几种现代编程语言(包括C ++,Java和C#)中,该语言允许整数溢出在运行时发生而不会引发任何类型的错误条件。



例如,考虑这个(设计的)C#方法,它不考虑溢出的可能性/下溢。 (为简洁起见,该方法也不处理指定列表为空引用的情况。)

  //返回指定列表中值的总和。 
private static int sumList(List< int> list)
{
int sum = 0;
foreach(列表中的int listItem)
{
sum + = listItem;
}
返还金额;
}

如果调用此方法如下:

  List< int> list = new List< int>(); 
list.Add(2000000000);
list.Add(2000000000);
int sum = sumList(list);

sumList()方法(因为C#中的 int 类型是一个32位有符号整数,并且列表中值的总和超过了最大32位有符号整数的值)。 sum变量的值为-294967296(不是值4000000000);这很可能不是sumList方法的(假设的)开发人员所期望的。



显然,开发人员可以使用各种技术来避免整数的可能性溢出,例如使用类似Java的 BigInteger ,或 已选中 关键字和 / checked 编译器在C#中切换。



然而,我感兴趣的问题是这就是为什么这些语言默认设计为允许整数溢出首先发生的原因,而不是,例如,在运行时执行操作会引发溢出时引发异常。看起来这样的行为有助于避免在编写执行可能导致溢出的算术运算的代码时开发人员忽略了解溢出的可能性的情况下的错误。 (这些语言可能包含类似未经检查的关键字,可以指定允许发生整数溢出而不会引发异常的块,在开发人员明确意图该行为的情况下; C#实际上确实有这个。)



答案是否简单归结为性能 - 语言设计者不希望他们各自的语言默认具有慢算术整数运算,其中运行时需要做额外的工作来检查是否发生溢出,在每个适用的情况下算术运算 - 这种性能考虑超过了在发生意外溢出的情况下避免无声失败的价值?



此语言设计决策还有其他原因吗?除了性能考虑因素之外?

解决方案

在C#中,这是一个性能问题。具体来说,是开箱即用的基准测试。



当C#是新的时,微软希望很多C ++开发人员能够切换到它。他们知道许多C ++人认为C ++是快速的,尤其比那些浪费时间在自动内存管理等上的语言更快。



潜在的采用者和杂志评论者都可能获得新C#的副本,安装它,构建一个在现实世界中没有人会写的简单应用程序,以紧凑的循环运行它,并测量它花了多长时间。然后他们会为他们的公司做出决定或根据该结果发布一篇文章。



他们的测试显示C#比本机编译的C ++慢的事实是那种可以迅速让人们远离C#的东西。您的C#应用​​程序将自动捕获溢出/下溢这一事实是他们可能会错过的事情。所以,它默认是关闭的。



我认为很明显我们想要/检查的时间是99%。这是一个不幸的妥协。


In several modern programming languages (including C++, Java, and C#), the language allows integer overflow to occur at runtime without raising any kind of error condition.

For example, consider this (contrived) C# method, which does not account for the possibility of overflow/underflow. (For brevity, the method also doesn't handle the case where the specified list is a null reference.)

//Returns the sum of the values in the specified list.
private static int sumList(List<int> list)
{
    int sum = 0;
    foreach (int listItem in list)
    {
        sum += listItem;
    }
    return sum;
}

If this method is called as follows:

List<int> list = new List<int>();
list.Add(2000000000);
list.Add(2000000000);
int sum = sumList(list);

An overflow will occur in the sumList() method (because the int type in C# is a 32-bit signed integer, and the sum of the values in the list exceeds the value of the maximum 32-bit signed integer). The sum variable will have a value of -294967296 (not a value of 4000000000); this most likely is not what the (hypothetical) developer of the sumList method intended.

Obviously, there are various techniques that can be used by developers to avoid the possibility of integer overflow, such as using a type like Java's BigInteger, or the checked keyword and /checked compiler switch in C#.

However, the question that I'm interested in is why these languages were designed to by default allow integer overflows to happen in the first place, instead of, for example, raising an exception when an operation is performed at runtime that would result in an overflow. It seems like such behavior would help avoid bugs in cases where a developer neglects to account for the possibility of overflow when writing code that performs an arithmetic operation that could result in overflow. (These languages could have included something like an "unchecked" keyword that could designate a block where integer overflow is permitted to occur without an exception being raised, in those cases where that behavior is explicitly intended by the developer; C# actually does have this.)

Does the answer simply boil down to performance -- the language designers didn't want their respective languages to default to having "slow" arithmetic integer operations where the runtime would need to do extra work to check whether an overflow occurred, on every applicable arithmetic operation -- and this performance consideration outweighed the value of avoiding "silent" failures in the case that an inadvertent overflow occurs?

Are there other reasons for this language design decision as well, other than performance considerations?

解决方案

In C#, it was a question of performance. Specifically, out-of-box benchmarking.

When C# was new, Microsoft was hoping a lot of C++ developers would switch to it. They knew that many C++ folks thought of C++ as being fast, especially faster than languages that "wasted" time on automatic memory management and the like.

Both potential adopters and magazine reviewers are likely to get a copy of the new C#, install it, build a trivial app that no one would ever write in the real world, run it in a tight loop, and measure how long it took. Then they'd make a decision for their company or publish an article based on that result.

The fact that their test showed C# to be slower than natively compiled C++ is the kind of thing that would turn people off C# quickly. The fact that your C# app is going to catch overflow/underflow automatically is the kind of thing that they might miss. So, it's off by default.

I think it's obvious that 99% of the time we want /checked to be on. It's an unfortunate compromise.

这篇关于为什么语言默认情况下不会在整数溢出上引发错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆