在几个的现代化编程语言(包括C++、Java和C#),语言允许 整溢出 发生在运行时没有提出任何类型的错误的条件。

例如,考虑这个(预谋)C#方法,该方法不考虑可能的溢/下溢。(为了简短起见,该方法也没有处理的情况下指定列表是空的参考。)

//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;
}

如果这种方法被称为如下:

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

溢出将发生在 sumList() 方法(因为 int 类型在C#是一个32位签署整数和总值在该列表中超过最大值的32位签署整数)。总变量有价值的-294967296(不值4000000000);这最有可能不是什么(假定的)开发sumList方法的目的。

显然,有各种技术,可用于开发人员,以避免可能的整数溢出,例如使用一个类似的Java BigInteger, 或 checked 关键字和 /checked 编译器开关。

然而,这个问题,我感兴趣的是你为什么这些语言的目的是通过默认允许整数溢出发生在首位,而不是的,例如,提高一个例外当作是在运行时执行,将会导致溢出。它似乎喜欢这样的行为将有助于避免错误的情况下,开发忽略要账户的可能性溢出时编写代码,用于执行一个算术运算,可能会导致溢出。(这些语言可能已经包括一些像"选中"关键词可能指定一块整数溢出允许出现毫无例外提出,在那些情况下,行为是明确地旨在通过开发;C#真的 不会有这个.)

没有答案简单地归结到性能的--语言的设计师不希望他们的各自语言为默认具有"减缓"整数的算术的操作运行时将需要做的额外工作以检查是否发生溢出,在每一适用的算术运算--而这个性能的考虑超过了价值以避免"无声的"故障的情况下,一个意外的溢出发生?

是否还有其他原因,这种语言设计的决定以及其他比性方面的考虑?

有帮助吗?

解决方案

在C#这是一个问题的性能。具体地说,出的基准。

当C#是新的,Microsoft希望很多C++开发人员会切换到它。他们知道,许多C++人认为C++为迅速,尤其是快于语言"浪费的"时间上的自动存管理等。

这两个潜在的使用者和杂志评论者有可能得到复制的新C#、安装,建立一个简单的应用程序,没有人会写在现实世界中,运行它在紧张的循环,并测量了多长时间.然后他们会作出决定,为他们的公司或发布的一篇文章根据这一结果。

事实上,他们的测试表明C#可以低于本地汇编C++的样的事情,将关闭的人C#快。事实上,你C#程序是要抓住溢/溢自动就是这种东西,他们可能错过。因此,它是默认。

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

其他提示

我认为表演是一个很好的理由。如果你考虑典型程序中的每个指令增加一个整数,并且如果不是简单的op添加1,它必须每次检查如果添加1会溢出该类型,那么额外周期中的成本将非常严重。

你假设整数溢出总是不受欢迎的行为。

有时整数溢出是期望的行为。我见过的一个例子是将绝对航向值表示为固定点数。给定unsigned int,0为0或360度,最大32位无符号整数(0xffffffff)是360度以下的最大值。

int main()
{
    uint32_t shipsHeadingInDegrees= 0;

    // Rotate by a bunch of degrees
    shipsHeadingInDegrees += 0x80000000; // 180 degrees
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees, overflows 
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees

    // Ships heading now will be 180 degrees
    cout << "Ships Heading Is" << (double(shipsHeadingInDegrees) / double(0xffffffff)) * 360.0 << std::endl;

}

可能还有其他情况可以接受溢出,类似于此示例。

C / C ++永远不会要求陷阱行为。即使是明显的除以0也是C ++中未定义的行为,而不是指定类型的陷阱。

除非你计算信号,否则C语言没有任何陷阱概念。

C ++有一个设计原则,它不会引入C中不存在的开销,除非你要求它。所以Stroustrup不希望强制整数的行为方式需要任何明确的检查。

一些早期编译器和受限硬件的轻量级实现根本不支持异常,并且通常可以使用编译器选项禁用异常。强制使用语言内置函数的异常会有问题。

即使C ++已经对整数进行了检查,99%的早期程序员也会因为性能提升而关闭...

因为检查溢出需要时间。每个原始数学运算(通常转换为单个汇编指令)都必须包含溢出检查,从而导致多个汇编指令,可能导致程序速度慢几倍。

可能性能达到99%。在x86上,必须检查每个操作的溢出标志,这将是一个巨大的性能损失。

另外1%将覆盖人们正在进行奇特的位操作或混合有符号和无符号操作并且想要溢出语义的“不精确”的情况。

向后兼容性是一个很大的问题。使用C,假设您对数据类型的大小给予了足够的重视,如果发生上溢/下溢,那就是您想要的。然后使用C ++,C#和Java,很少改变“内置”和“内置”的方式。数据类型工作。

我理解为什么在运行时默认不会引发错误,这归结为希望创建具有类似ACID行为的编程语言的遗产。具体来说,你编写任何代码来做(或不做代码)的原则,它会做(或不做)。如果你没有编写一些错误处理程序,那么机器将“假设”由于没有错误处理程序,你真的想要做你告诉它要做的荒谬,容易崩溃的事情。

(ACID参考: http://en.wikipedia.org/wiki/ACID

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top