Переполнение типа

Ещё один очень важный аспект работы с типами данных - это переполнение.

Мы уже косвенно сталкивались с ним при рассмотрении небезопасного преобразования типов, но давайте поговорим об этом подробнее.

Что это такое

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

Можно себе представить аналогию с коробками и песком. Если переменная (коробка) занимает определённое количество памяти (вмещает в себя определённое количество песка), и мы пытаемся положить в неё слишком "большие" данные (засыпаем в неё слишком большое количество песка), часть данных будет потеряна (часть песка просто высыпется).

Частично переполнение уже обсуждалось в статье про приведение типов, в разделе о небезопасных преобразованиях - там мы разбирали, что происходит, когда мы пытаемся в переменную типа char сложить число 300.

Пример переполнения

Предположим, что в переменной char a уже лежит число 127. В бинарном виде это будет выглядеть как:

01111111

Тип char формально может принимать и отрицательные значения, поэтому первый бит, по аналогии с int, равен 0.

Что же будет, если мы попытаемся к переменной a добавить ещё единицу? Результат в принципе будет предсказуем. Бинарное представление переменной будет выглядеть так:

10000000

Как видим, первый бит теперь равен 1 - а это для типа char это означает, что число отрицательное. Далее, за битом знака, идут только нули. -0 автоматически переведётся в -128.

Получается, мы хотели в char положить 128, а получилось, что там теперь лежит -128.

Аналогично, если мы попытаеимся в char положить заведомо слишком большое число, например 300:

100101100 -> 1[00101100]

Квадратными скобками здесь я выделил часть числа 300, которая непосредственно будет записана в переменную char. Таким образом, мы запишем в переменную не число 300, а число \( 101100_2 = 44_{10} \).

Последствия переполнений переменных в реальном мире

Как я уже говорил, в истории человечества было множество примеров, когда неправильная работа с типами данных в С/C++ приводила к катастрофическим последствиям. Когда-то это были потерянные огромные суммы денег, когда-то это были реальные человеческие жертвы. Иногда это просто вызывало небольшой дискомфорт для пользователей программы, но всё равно критичность ошибки это сильно не меняет.

Therac-25

В 1985-1987 медицинской аппаратурлй Therac-25 смертельной дозой радиации были убиты 6-7 человек.

Причиной послужила неправильная работа с многопоточностью и возникший вследствие этого integer overflow (переполнение переменной int).

На эту тему есть отличное видео-эссе, которое я оставил в источниках.

Баги в видеоиграх

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

Наверное, самый легендарный пример - это сломанный экран в пакмане

Если играть достаточно долго, переменная с номер уровня переполняется, и экран уровня заполняется случайными символами, из-за которых пройти игру становится невозможно.


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

Просто если их не учитывать, по уровню разработки вы откатитесь на 20-30 лет назад.

Источники

  1. Integer overlow - Wiki
  2. History's Worst Software Error - Youtube