27. Обработка программных прерываний

Программное прерывание - это ситуация, возникающая при выполнении про­граммы, когда нормальное выполнение невозможно. Например: деление на ноль, переполнение, Range Check Error, обращение по неверному адресу, попытка открыть для чтения несуществующий файл и т.п. Обычная реакция программы на такие события - вывод сообщения об ошибке и аварийное завершение. Одна­ко, пользуясь стандартными средствами Turbo Pascal^, вы можете предусмотреть в своих программах и любую другую реакцию на прерывания. Для этого исполь­зуются переменные ExitProc, ExitCode, ErrorAdr и процедура RunError.

Переменная - указатель ExitProc может содержать адрес процедуры, которая станет обрабатывать программные прерывания. Эта процедура не может иметь параметров и должна быть откомпилирована с опцией {$F+}. Если такая проце­дура предусмотрена в программе, ее адрес (с помощью операции @) нужно при­своить переменной ExitProc. После этого данная процедура будет вызываться всякий раз, когда произойдет программное прерывание. Следует учитывать, что нормальное завершение программы и остановка программы процедурой Halt также являются прерываниями, и, следовательно, процедура будет выполняться при любом завершении программы. Запишем пока тривиальную программу:

{$F+}

PROCEDURE MyExitProc;

BEGIN WRITELN('произошло прерывание !!!'); END; {$F-}

VAR x : REAL;

BEGIN ExitProc:=@MyExitProc; WRITE('Введите число '); READ(x);

WRITELN^to число в степени 33.3 равно ',Exp(33.3*Ln(x)));

END.

Запустим программу и введем число 10, программа выведет на экран резуль­тат, а затем сообщение "произошло прерывание!!!". Теперь введем число 20 -программа выведет сообщение "это число в степени 33.3 равно произошло прерывание !!!", затем сообщение об ошибке "Runtime error 205 at 0000:00F9", т.е. завершится все равно аварийно. Используем теперь переменные ExitCode и ErrorAddr, которые возвращают:

- при нормальном завершении ExitCode = 0 , ErrorAddr = NIL;

- при выполнении процедуры Halt ExitCode = аргументу Halt , ErrorAddr =

NIL;

- при аварийном завершении ExitCode = коду ошибки, ErrorAddr = адресу прерывания.

Будем выводить сообщение только при аварийном завершении, т.е. когда ErrorAddr не равен NIL, и менять в этом случае значение ErrorAddr, чтобы предотвратить появление стандартного сообщения об ошибке:

PROCEDURE MyExitProc;

BEGIN IF ErrorAddr<>NIL THEN BEGIN

WRITELN('произошло прерывание !!!'); ErrorAddr:=NIL; END;

END;

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

PROCEDURE MyExitProc;

BEGIN IF ErrorAddr<>NIL THEN BEGIN

WRITE('Произошло прерывание'); CASE ExitCode OF

106 : WRITELN(' (ошибка ввода)');

207 : WRITELN(' (отрицательное число нельзя',

' возводить в вещественную степень)'); 205 : WRITELN(' (слишком большое число)'); ELSE WRITELN(' (неизвестная ошибка)');

END;

ErrorAddr:=NIL;

END;

Введем "abc" - программа сообщит "ошибка ввода"; введем "-2" - программа сообщит "отрицательное число нельзя возводить в вещественную степень"; введем "100" - программа сообщит "слишком большое число". Процедура

PROCEDURE RunError(Errorcode:Byte) используется главным образом при отладке программ, она генерирует прерыва­ние с заданным кодом. Например, для полной проверки нашей процедуры вста­вим в текст программы оператор RunError(200); - программа сообщит "неиз­вестная ошибка".