Почему вы хотите, чтобы произошло целочисленное переполнение? - PullRequest
25 голосов
/ 03 февраля 2011

В этом вопросе тема состоит в том, как заставить VS проверять арифметическое переполнение в C # и выдавать исключение: C # Переполнение не работает?Как включить проверку переполнения?

В одном из комментариев было сказано что-то странное и за него проголосовали. Надеюсь, вы мне поможете:

Вы также можете использоватьпроверенное ключевое слово, чтобы обернуть оператор или набор операторов, чтобы они были явно проверены на арифметическое переполнение.Установка свойства для всего проекта немного рискованно, потому что часто переполнение - вполне разумное ожидание.

Я не очень разбираюсь в оборудовании, но знаю, что переполнение связано с тем, как работают регистры.Я всегда думал, что переполнение вызывает неопределенное поведение и должно быть предотвращено, где это возможно.(в «обычных» проектах, без написания вредоносного кода)

Зачем вам ожидать, что произойдет переполнение, и почему бы вам не предотвратить его, если бы у вас была такая возможность?(установив соответствующую опцию компилятора)

Ответы [ 13 ]

35 голосов
/ 03 февраля 2011

Основное время, когда я хочу переполнение , - это вычисление хеш-кодов. Там фактическая числовая величина результата вообще не имеет значения - фактически это всего лишь битовый паттерн, которым я управляю с помощью арифметических операций.

Мы проверили арифметику, включенную во всем проекте для Время Noda - я скорее выброшу исключение, чем верну неправильные данные. Я подозреваю, что переполнения довольно редки, чтобы быть желательными ... Я признаю, что я обычно оставляю по умолчанию непроверенную арифметику, просто потому что это по умолчанию. Конечно, есть и штраф за скорость ...

10 голосов
/ 03 февраля 2011

Я всегда думал, что переполнение вызывает неопределенное поведение и его следует по возможности предотвращать.

Вы также можете быть смущены разницей между переполнением буфера (переполнением) и числовым переполнением.

Переполнение буфера - это когда данные записываются после конца неуправляемого массива.Это может вызвать неопределенное поведение, например, перезаписать адрес возврата в стеке данными, введенными пользователем.Переполнение буфера трудно сделать в управляемом коде.

Числовое переполнение, однако, хорошо определено.Например, если у вас есть 8-битный регистр, он может хранить только 2 ^ 8 значений (от 0 до 255, если не подписано).Поэтому, если вы добавите 100 + 200, вы получите не 300, а 300 по модулю 256, то есть 44. История немного сложнее с использованием подписанных типов;битовая комбинация увеличивается аналогичным образом, но они интерпретируются как дополняют два , поэтому добавление двух положительных чисел может дать отрицательное число.

9 голосов
/ 03 февраля 2011

При выполнении расчетов с постоянно увеличивающимися счетчиками.Классическим примером является Environment.TickCount:

int start = Environment.TickCount;
DoSomething();
int end = Environment.TickCount;
int executionTime = end - start;

Если этот флажок установлен, у программы есть шансы на взрыв через 27 дней после загрузки Windows.Когда TickCount тикает за пределы int.MaxValue во время работы DoSomething.PerformanceCounter - другой пример.

Эти типы вычислений дают точный результат, даже если присутствует переполнение.Вторым примером является вид математики, которую вы используете для генерации репрезентативной битовой комбинации, вас не очень интересует точный результат, просто воспроизводимый.Примерами этих являются контрольные суммы, хэши и случайные числа.

5 голосов
/ 03 февраля 2011

Уголки

Переполненные целые числа - элегантные инструменты для измерения углов. У вас 0 == 0 градусов, 0xFFFFFFFF == 359,999 .... градусов. Это очень удобно, потому что как 32-битные целые числа вы можете добавлять / вычитать углы (350 градусов плюс 20 градусов заканчиваются переполнением на 10 градусов) Также вы можете использовать 32-разрядное целое число как со знаком (от -180 до 180 градусов) и без знака (от 0 до 360). 0xFFFFFFF равняется -179,999 ..., что равняется 359,999 ..., что эквивалентно. Очень элегантно.

3 голосов
/ 03 февраля 2011

Вероятно, это связано как с историей, так и с любыми техническими причинами.Целочисленное переполнение очень часто использовалось для достижения хорошего эффекта алгоритмами, основанными на поведении (в частности, алгоритмами хеширования).

Кроме того, большинство ЦП предназначены для разрешения переполнения, но в процессе устанавливают бит переноса,облегчает реализацию сложения по сравнению с длинами слов, превышающими натуральные.Реализовывать проверенные операции в этом контексте означало бы добавление кода, чтобы вызвать исключение, если установлен флаг переноса.Не большая навязка, но та, которую авторы компилятора, вероятно, не хотели навязывать людям без выбора.

Альтернативой было бы проверять по умолчанию, но предлагать непроверенную опцию.Почему это не так, вероятно, восходит к истории.

3 голосов
/ 03 февраля 2011

При создании HashCodes, скажем, из строки символов.

3 голосов
/ 03 февраля 2011

почему бы вам не предотвратить это, если бы у вас была такая возможность?

Причина, по которой проверенная арифметика не включена по умолчанию, заключается в том, что проверенная арифметика медленнее, чем непроверенная арифметика.Если производительность не является для вас проблемой, возможно, имеет смысл включить проверенную арифметику, поскольку возникновение переполнения обычно является ошибкой.

2 голосов
/ 03 февраля 2011

Вы могли бы ожидать это на чем-то, что измеряется для дельт. Некоторое сетевое оборудование поддерживает малые размеры счетчиков, и вы можете запрашивать значения, например, переданные байты. Если значение становится слишком большим, оно просто возвращается к нулю. Это все еще дает вам что-то полезное, если вы измеряете это часто (байты / минуты, байты / часы), и, поскольку счетчики обычно очищаются при разрыве соединения, не имеет значения, что они не совсем точны.

Как упоминал Джастин, переполнение буфера - это другой котелок рыбы. Это то место, где вы записываете конец массива в память, чего не следует делать. В числовом переполнении используется тот же объем памяти. При переполнении буфера вы используете память, которую вы не выделяли. Переполнение буфера предотвращается автоматически на некоторых языках.

1 голос
/ 03 февраля 2011

Это связано не столько с тем, как работают регистры, сколько с ограничениями памяти в переменных, которые хранят данные.(Вы можете переполнить переменную в памяти без переполнения регистров.)

Но чтобы ответить на ваш вопрос, рассмотрим простейший тип контрольной суммы.Это просто сумма всех проверяемых данных.Если контрольная сумма переполняется, это нормально, а та часть, которая не переполнена, все еще имеет смысл.

Другие причины могут включать то, что вы просто хотите, чтобы ваша программа продолжала работать, даже если переполнена несущественная переменная.

1 голос
/ 03 февраля 2011

Существует одна классическая история о программисте, который воспользовался переполнением при разработке программы:

История Мела

...