在几种现代编程语言(包括 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位有符号整数的值)。sum 变量的值为 -294967296(不是 4000000000);这很可能不是 sumList 方法的(假设的)开发人员想要的。
显然,开发人员可以使用多种技术来避免整数溢出的可能性,例如使用 Java 之类的类型BigInteger
,或者 C# 中的checked
关键字和/checked
编译器开关。
但是,我感兴趣的问题是为什么这些语言被设计为默认情况下首先允许整数溢出发生,而不是例如在运行时执行操作时引发异常,这会导致溢出。如果开发人员在编写执行可能导致溢出的算术运算的代码时忽略了溢出的可能性,这种行为似乎有助于避免错误。(这些语言可能包含类似“unchecked”关键字之类的东西,它可以指定一个允许发生整数溢出而不引发异常的块,在开发人员明确意图该行为的情况下;C# 实际上确实有 this . )
答案是否简单地归结为性能 - 语言设计者不希望他们各自的语言默认具有“慢”算术整数运算,运行时需要做额外的工作来检查每个适用的算术是否发生溢出操作——在发生意外溢出的情况下,这种性能考虑是否超过了避免“静默”故障的价值?
除了性能方面的考虑之外,这种语言设计决策还有其他原因吗?