Как не следует делать это - C-Unix пример


Обработка исключений

 

Теперь у нас есть определение того, что может случиться, - исключения - и того, с чем мы бы не хотели столкнуться в результате появления исключения, - отказа. Давайте разыскивать способы справляться с исключениями так, чтобы не возникли отказы. Что может сделать программа, когда ее выполнение прервано из-за нежелательного поведения?

Помощь в нахождении разумного ответа могут дать примеры того, как не следует поступать в подобных ситуациях. Ими мы обязаны механизму сигналов языка C, пришедшему из Unix, и одному учебнику по языку Ada.

 

 

Первым контрпримером механизма (наиболее полно представленным в Unix, но доступным и на других платформах, реализующих C) является процедура signal , вызываемая в следующей форме:

 

signal (signal_code, your_routine)

 

 

с эффектом вызова обработчика исключения - программы your_routine , когда выполнение текущей программы прерывается, выдавая соответствующий код сигнала (signal_code ). Код сигнала - целочисленная константа, например, SIGILL (неверная инструкция - illegal instruction ) или SIGFPE (переполнение с плавающей точкой - floating-point exception ). В программу можно включить сколь угодно много вызовов процедуры signal , что позволяет обрабатывать различные, возможные ошибки.

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

Что необходимо в большинстве подобных случаев - исправить ситуацию и продолжить выполнение, начиная с некоторой особой точки, но не точки прерывания. Мы увидим, что есть простой механизм, реализующий эту схему. Заметьте, он может быть реализован и на C, на большинстве платформ. Достаточно комбинировать процедуру signal с двумя другими библиотечными процедурами: setjmp , вставляющую маркер в точку, допускающую продолжение вычислений, и longjmp для возврата к маркеру. С механизмом setjmp-longjmp следует обращаться весьма аккуратно. Поэтому он не ориентирован на обычных программистов, но может использоваться разработчиками компиляторов для реализации высокоуровневого механизма ОО-исключений, который будет описан в этой лекции.