В нескольких современных языках программирования (включая C++, Java и C#), язык позволяет integer overflow встречаться во время выполнения без повышения какого-либо состояния ошибки.Почему языки по умолчанию не повышают ошибки при переполнении целых чисел?
Например, рассмотрим этот (надуманный) метод 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# фактически does have this.)
Отвечает ли ответ просто на производительность - разработчики языка не хотели, чтобы их соответствующие языки по умолчанию имели «медленные» арифметические операции с целыми числами, в которых время выполнения должно было выполнять дополнительную работу, чтобы проверить, произошло ли переполнение, каждая применимая арифметическая операция - и это соображение производительности перевешивало ценность предотвращения «молчащих» сбоев в случае непреднамеренного переполнения?
Существуют ли другие причины для этого решения по языковому дизайну, помимо соображений эффективности?
Не возвращается ли ЦП флаг при переполнении операции? (Конечно, проверка этого флага также требует времени). – Thilo 2017-03-24 04:28:51
@Thilo есть процессоры без каких-либо флагов, таких как MIPS. Даже делать простые операции с большим int на них - небольшая боль – 2017-08-14 07:59:33