Директивы inline предназначены только для очень коротких (менее 10 байтов) процедур и функций в машинных кодах. Из-за того, что процедуры и функции с директивой inline являются макроопределениями, к ним неприменимы операции взятия адреса (оператор @, функции Addr, Ofs и Seg).

<p>14.8. Процедура завершения и обработка ошибок программ</p>

Если действия написанной программы вступают в противоречие с вычислительными возможностями ПЭВМ или требуют невозможного от ее ресурсов, то они, как правило, прерываются с выдачей сообщения типа «Runtime Error NNN». В таком случае мы говорим о фатальной ошибке времени счета (или во время счета). Такие ошибки могут возникать при запросах на размещение динамических переменных при малом объеме свободной памяти, попытках записи на переполненный диск, чтении с пустых дисководов, делениях на нуль или при нарушениях области допустимых значений аргументов функций Sqrt, Ln и т.д. Список этот можно продолжить. Общим для всех этих причин является то, что неизвестно, где и как они могут

- 308 -

возникнуть. Как правило, ошибки, не связанные с вводом-выводом, возникают из-за недосмотров в логическом построении программ. Причем хорошо, если все закончится выдачей текста «Runtime Error...», ведь программа может «зависнуть» так, что разблокировать ПЭВМ можно будет только полным перезапуском...

Все ошибки времени счета можно разделить на условно и безусловно фатальные. Условно фатальные ошибки — это те, которые могут блокироваться соответствующими режимами компиляции. Например, ошибка при проверке диапазонов с кодом 201 (Range Check Error) может появиться лишь, если программа откомпилирована в режиме {$R+}, ошибка 202 — переполнение стека (Stack Overflow) — в режиме {$S+}. К условно фатальным можно отнести все ошибки, связанные с вводом-выводом (коды ошибок 2-199), подробно рассмотренные в гл. 12. Отключение соответствующих режимов контроля ошибок вовсе не повышает безошибочность программ. Оно всего лишь загоняет «болезнь» программы внутрь и дает лишний повод усомниться в корректности выдаваемых программой ответов. Безусловно фатальные ошибки — это такие, которые нельзя ничем заблокировать. Сюда относятся все ошибки вычислений с плавающей точкой и некоторые другие.

Мы уже обсуждали способы обработки ошибок ввода-вывода и ошибок при распределении памяти (см. разд. 12.11, 11.5.6). Ниже будет рассмотрен способ обработки фатальных ошибок.

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

Механизм подстановки процедуры несложен. Вот его алгоритм:

1. Пишется процедура завершения программы. Это вполне обычная процедура. Требования к ней таковы: она не должна иметь параметров и должна быть откомпилирована в режиме {$F+}. Кроме того, в ней необходимо предпринять ряд действий по обработке ошибок и восстановлению системных адресов.

2. Объявляется переменная, например, с именем OldExitProc, имеющая тип Pointer.

- 309 -

3. В самом начале программы запоминается значение предопределенной системной переменной ExitProc — адрес стандартной процедуры завершения. Оно записывается в объявленную ранее переменную (у нас — в OldExitProc). А в ExitProc записывается значение адреса новой процедуры выхода.

4. Тело новой процедуры завершения должно начинаться с восстановления старого значения ExitProc. Далее, необходимо как бы обнулить системный указатель на фатальную ошибку (даже если ее не будет в действительности, это не повредит), записав в системную переменную ErrorAddr значение nil. Если этого не сделать, то после выполнения анализа ошибки и других действий на экран может вылезти уже не нужное «Runtime Error...».

Подставленная таким образом процедура всегда будет выполняться при завершении программы: будь то естественное завершение, выход по команде Halt или останов из-за ошибки.

Хотя по определению процедура выхода не содержит параметров, ей доступно значение кода ошибки и кодов завершения, посылаемых оператором Halt(N). Они хранятся в системной переменной ExitCode типа Integer. Совместно со значением адреса ErrorAddr переменная ExitCode определяет причину остановки программы (N — значение ExitCode):

ExitCode=0

ExitCode<>0

ErrorAddr= nil

Естественное завершение

Выход по Halt(N)

ErrorAddr<> nil

Не может быть

Ошибка N

Если программа была прервана пользователем с помощью комбинации клавиш Ctrl+Break, то в ExitCode запишется значение 255. Рассмотрим пример подстановки процедуры завершения (рис. 14.7).

Перейти на страницу:

Поиск

Похожие книги