- •От автора
- •1. Общая схема решения задачи на персональном компьютере
- •2. Структура программы на языке Паскаль
- •3. Арифметические типы данных. Числовые константы и переменные. Оператор присваивания. Выражение
- •4. Операторы ввода-вывода
- •5. Арифметические операции. Стандартные математические функции
- •6. Символьный тип данных
- •7. Логический тип данных. Операции сравнения. Логические операции
- •8. Условный оператор. Блок. Оператор выбора
- •9. Операторы цикла
- •10. Метки. Оператор Goto. Процедура Halt
- •11. Интервальные типы данных. Оператор Type. Массивы
- •Var a : Array[1..33000] Of Word;
- •Var a : Array[1..3] Of Real;
- •Var e,f : Massiv;
- •Var a : Array[1..10] Of Array[1..20] Of Real;
- •12. Процедуры и функции. Сфера действия описаний
- •13. Открытые массивы и нетипизированные параметры
- •14. Множества
- •15. Тип String
- •16. Графические средства языка Паскаль
- •17. Особенности вещественных вычислений
- •18. Записи
- •19. Тип "перечисление"
- •20. Модуль Crt
- •Var TextAttr : Byte
- •21. Модули. Создание и использование модулей
- •Interface
- •Implementation
- •22. Файлы
- •23. Другие средства обработки файлов и модуль dos
- •24. Процедурные типы
- •25. Указатели и динамическая память
- •26. Динамические структуры: списки, деревья
- •27.Открытые строки
- •28. Использование командной строки и вызов внешних программ
- •29. Обработка программных прерываний
- •30. Объекты
- •31.Рекурсия и динамическое программирование
- •32. Рекурсия и стек отложенных заданий
- •33. Стеки и очереди
- •34. Комбинаторные алгоритмы
- •35. Бинарные деревья
- •36. Упорядоченные бинарные деревья и приоритетные очереди
- •37. Алгоритмы сортировки
- •38. Графы
- •Рекомедуемая литература
- •Содержание
29. Обработка программных прерываний
Программное прерывание - это ситуация, возникающая, когда дальнейшее выполнение программы невозможно. Например, деление на ноль, переполнение, ошибка Range check error, обращение по неверному адресу, попытка открыть для чтения несуществующий файл и т.п. Обычная реакция программы на такие события - вывод сообщения об ошибке и аварийное завершение. Мы уже знаем, как предотвращать возникновение некоторых из этих ошибок. Но Паскаль предоставляет программисту возможность обработки прерывания уже после того, как оно произошло. Для этого используются стандартные переменные ExitProc, ExitCode, ErrorAdr и процедура RunError.
Переменная ExitProc типа Pointer может содержать адрес процедуры, которая будет обрабатывать программные прерывания. Эта процедура должна иметь дальний адрес. Если такая процедура предусмотрена в программе, ее адрес (с помощью операции @) нужно присвоить переменной ExitProc. После этого данная процедура будет вызываться всякий раз, когда произойдет программное прерывание. Следует учитывать, что нормальное завершение программы и остановка программы процедурой Halt также являются прерываниями и, следовательно, процедура будет выполняться при любом завершении программы. Запишем пока тривиальную программу:
Procedure MyExitProc; Far;
Begin
WriteLn('произошло прерывание');
End;
Var x : Real;
Begin
ExitProc:=@MyExitProc;
Write('Введите число ');
Read(x);
WriteLn('это число в степени 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(n) ExitCode = n, 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(' (основание степени <0'));
205 : WriteLn(' (слишком большое число)');
Else WriteLn(' (неизвестная ошибка)');
End;
ErrorAddr:=Nil;
End;
End;
Введем “abc” - программа сообщит “ошибка ввода”; введем “-2” - программа сообщит “основание степени отрицательно”; введем “100” - программа сообщит “слишком большое число”. Процедура
Procedure RunError(Errorcode:Byte);
используется главным образом при отладке программ, она генерирует прерывание с заданным кодом. Например, для полной проверки нашей процедуры вставим в текст программы оператор RunError(200); - программа сообщит “неизвестная ошибка”. Это был самый простой пример использования средств обработки прерываний - мы использовали одну нерекурсивную процедуру. Программа может содержать много процедур, обрабатывающих прерывания, и в разных местах программы может быть записано любое количество операторов ExitProc:=@процедура; Кроме того, такие операторы могут быть внутри самой процедуры-обработчика или она может быть рекурсивной, тогда при любом прерывании начнет работать так называемая цепочка процедур, обрабатывающих прерывания. Не составляет большого труда написать программу, в которой весь алгоритм будет записан в процедуре-обработчике прерываний, а главная программа будет состоять всего из двух операторов
ExitProc:=@процедура; RunError(код ошибки);
а все остальное будет делать процедура-обработчик прерываний (или несколько таких процедур), которая будет сразу же вызвана, так как RunError сгенерирует прерывание с заданным кодом.