Основы программирования

Использование функции assert для проверки утверждений и ситуация отказ


В реализации стека на Си неоднократно использовалась функция assert, в переводе с английского "утверждение". Фактическим аргументом функции является логическое выражение. Если оно истинно, то ничего не происходит; если ложно, то программа завершается аварийно, выдавая диагностику ошибки.

Функция assert является реализацией конструкции "утверждение", использование которой преследует две цели:

  1. программист в процессе написания программы может явно сформулировать утверждение, которое, по его мнению, должно выполняться в данной точке программы. В этом случае конструкция "утверждение" выполняет роль комментария, облегчая создание и понимание программы;
  2. компьютер при выполнении программы проверяет все явно сформулированные утверждения. Истинность утверждения соответствует предположениям программиста, сделанным в процессе написания программы, поэтому выполнение программы продолжается. Ложность утверждения свидетельствует об ошибке программиста. При этом выдается сообщение об ошибке и выполнение программы немедленно прекращается. Таким образом, конструкция "утверждение " позволяет компьютеру проверять корректность программы непосредственно в процессе ее выполнения.

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

Многие предписания структуры данных выполнимы не во всех ситуациях. Например, элемент можно взять из стека только в случае, когда стек не пуст. Поэтому перед началом выполнения предписания "Взять элемент" проверяется условие "стек не пуст":

double st_pop() { // Взять элемент: вещ assert(sp >= 0); // утв: стек не пуст . . .

Если это утверждение ложно, то возникает ситуация "отказ ": компьютер завершает работу, выдавая диагностику ошибки. Невыполнение утверждения всегда свидетельствует об ошибке программиста: программа должна быть написана таким образом, чтобы некорректные исходные данные не приводили к отказу.

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

Почему в случае невыполнения утверждения возникает ситуация "отказ"? Альтернативой могло бы быть игнорирование некорректной ситуации и то или иное продолжение программы: например, при попытке извлечения элемента из пустого стека выдавался бы ноль. На самом деле это худшее решение из всех, которые только можно придумать! Любую ошибку надо диагностировать и исправлять как можно раньше, а имитация полезной деятельности в некорректной ситуации крайне опасна. Это может привести, например, к тому, что программа, управляющая посадкой самолетов, будет успешно сажать в среднем 999 самолетов из 1000, а каждый тысячный будет разбиваться.

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

При частом использовании конструкции "утверждение" возникает проблема с уменьшением скорости выполнения программы. Она решена в языках Си и C++ следующим образом: на самом деле конструкция assert в Си — это не функция, а макроопределение, которое обрабатывается препроцессором. Текст Си-программы может транслироваться в двух режимах: отладочном и нормальном. В нормальном режиме в соответствии со стандартом ANSI определена переменная NDEBUG препроцессора. Для определения макрокоманды assert используется условная трансляция: если переменная NDEBUG определена, то assert определяется как пустое выражение; если нет, то assert определяется как проверка условия и вызов функции _assert (к имени добавлен символ подчеркивания) в случае, когда условие ложно.Функция _assert печатает диагностику ошибки и завершает выполнение программы, т.е. реализует ситуацию "отказ".

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


Содержание раздела