TURBO PASCAL

Новости

Программы   

Turbo Pascal 

Игры

Документация   

Странности

FAQ

Ссылки

Форум

Гостевая книга

Рассылка

Благодарности

Об авторе

 

 

2.1. МЕХАНИЗМ ОБРАБОТКИ ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ

Для обработки исключительных ситуаций в Турбо Паскале предусмотрены соответствующие средства: в стандартный модуль System включена переменная ExitProc, с помощью которой можно перехватить управление программой в момент возникновения исключительной ситуации. По умолчанию эта переменная (она имеет тип Pointer) хранит значение NIL; если поместить в нее адрес некоторой процедуры пользователя (назовем ее процедурой выхода), то при возникновении исключительной ситуации управление передается в эту процедуру. Процедура выхода должна быть процедурой без параметров. Ее следует транслировать в расчете на дальнюю модель памяти.

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

Runtime error nnn at xxxx:yyyy,

где nnn — код (номер) ошибкИг -хххх: уууу — адрес той инструкции в коде программы, при выполнении которой возникла исключительная ситуация. Код ошибки и адрес ее возникновения хранятся в переменных ExitCode и ErrorAddr модуля System. Если в момент завершения программы эти пе

ременные имеют значения соответственно 0 и NIL, никакого сообщения не выдается.

Создадим новый модуль с именем UsrE-xit, в интерфейсной части которого будет объявлена процедура UserExit. Эту процедуру может использовать любая программа для выдачи развернутой диагностики в момент аварийного завершения:

{=============} UNIT UsrExit; {=====^=========}

INTERFACE var

OldExit: Pointer; {Старое значение ExitProc} Procedure UserExit;

{Процедура выхода. Осуществляет печать диагностического

сообщения и завершает работу программы.} Function HexB(b: Byte): String;

{Перевод байта в 16-ричное представление} Function HexW(n: Word): String;

{Перевод слова в 16-ричное представление}

IMPLEMENTATION Procedure UserExit;

{Процедура выхода. Осуществляет печать диагностического

сообщения и завершает работу программы.} var

txt: String;

begin {UserExit}

ExitProc := OldExit; {Восстанавливаем работу

стандартной процедуры выхода}

WriteLn ('Ошибка при выполнении программы');

case ExitCode of

1: txt := 'Неверный номер функции';

2: txt := 'He найден файл';

3: txt := 'He найден путь';

4: txt := 'Слишком много открытых файлов';

5: txt ^ 'Отказано в доступе к файлу';

6: txt := 'Недопустимый файловый дескриптор';

12: txt := 'Недопустимый код доступа к файлу';

15: txt := 'Недопустимый номер дисковода';

16: txt := "Нельзя удалить текущий каталог';

17: txt := 'Нельзя указывать разные дисководы';

100: txt := 'Ошибка чтения с диска';

101: txt := 'Ошибка записи на диск';

102: txt := 'Файлу не присвоено имя';

103: txt := 'Файл не открыт';

104: txt := 'Файл не открыт для ввода';

105: txt := 'Файл не открыт для вывода';

106: txt := 'Неверный числовой формат';

150: txt := 'Диск защищен от записи';

151: txt :== 'Неизвестный модуль';

152: txt := 'Не готов диск';

153: txt := 'Неопознанная команда';

154: txt := 'Ошибка в исходных данных';

155: txt := 'Неверная длина структуры';

156: txt := 'Ошибка установки головок на диске';

157: txt := 'Неизвестный тип носителя';

158: txt := 'He найден сектор';

159: txt := 'Кончилась бумага на принтере';

160: txt := 'Ошибка при записи на устройство';

161: txt := 'Ошибка при чтении с устройства';

162: txt := 'Сбой аппаратуры';

200: txt := 'Деление на ноль';

201: txt := 'Ошибка при проверке границ';

202: txt := 'Переполнение стека';

203: txt := 'Переполнение кучи';

204: txt := 'Недействительная операция с указателем';

205: txt := 'Переполнение при операции с пл.зпт.';

206: txt := 'Исчезновение порядка при операции '+ 'с плавающей запятой.';

207: txt := 'Недопустимая операция с плавающей запятой';

208: txt := 'He инициирован оверлей';

209: txt := 'Ошибка чтения оверлейного файла'

else txt := 'Ошибка N'+Str(ExitCode);

end; {case}

WriteLn(txt,' по адресу ',

HexW(seg(ErrorAddr^)),':',HexW(ofs(ErrorAddr"))) ;

ExitCode := 0;

ErrorAddr := NIL end; /UserExit} ^——————————————————J

Function HexB(b: Byte): String;

{Перевод байта в 16-ричное представление} const ^

HD: array [O..15] of Char = ('0','1','2','3','4','5','6', '7','8','9','A','B",'C','D','E','F');

begin {HexB}

HexB := HD[b shr 4]+HD[b and $F] end; {HexB} _•—__——_————————————_

Function HexW(n: Word): String;

{Перевод слова в 16-ричное представление} begin {HexW}

HexW := HexB(Hi(n))+HexB(Lo(n)) end; {HexW} end. {Unit UsrExit}

Обратите внимание: процедуру UserExit вовсе не обязательно объявлять дальней (с помощью зарезервированного слова Far), т.к. любая подпро

грамма, объявленная в интерфейсной части модуля, автоматически транслируется в расчете на дальнюю модель памяти.

В процедуре UserExit используется глобальная переменная OldExit. В нее программа пользователя должна поместить первоначальное значение переменной ExitProc, чтобы осуществились все необходимые стандартные действия, связанные с завершением работы программы. Для вывода адреса ошибочного оператора содержимое переменной ErrorAddr преобразуется в 16—ричный формат с помощью функции HexW. Такое преобразование может использоваться в программе пользователя и для других целей, поэтому функция HexW и вспомогательная функция НехВ также объявлены в интерфейсной части модуля.

Использование процедуры UserExit проиллюстрируем следующей

простой программой:

^———————————————————————————+

¦ Пример использования процедуры UserExit \

¦ для контроля работы программы \ -,-._——_——_—————.—,—————————————+_

Pses UsrExit;

var

x,y,z: real;

begin

OldExit := ExitProc; {Сохраняем старое значение ExitProc} ExitProc := @UserExit; {Указываем адрес процедуры UserExit} repeat

Write('X,Y= '); {Просим ввести операнды}

ReadLn(x,y); (Вводим операнды}

z := х/у; {Вычисляем их отношение}

WriteLn(z:15:7) {Выводим результат} until z=0;

ExitProc := OldExit {Готовим стандартное завершение} end.

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

ReadLn(x,y),

если будет нарушен требуемый формат задания вещественных чисел (например, в записи числа будет указан недопустимый символ), или в операторе

z := х/у,

если делитель равен нулю.

Если Вы решите использовать подобную процедуру в Вашей программе, не забудьте восстановить стандартное значение NIL в переменной ExitProc перед завершением ее работы, в противном случае возможно «зависание» программы со всеми вытекающими отсюда последствиями.

 

Глава 2

Оглавление

На первую страницу

Rambler's Top100 Rambler's Top100
PROext: Top 1000

(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz