Во втором элементе структуры EXCEPTION_POINTERS, а именно, элементе ContextRecord, содержится информация, относящаяся к процессору. Для каждого типа процессоров предусмотрены свои структуры, определения которых содержатся в файле .
Резюме: последовательность обработки исключений
На рис. 4.2 в схематическом виде представлена последовательность событий, происходящих после возникновении исключения. Слева приведен программный код, а обведенные кружками цифры справа обозначают операции, выполняемые языковыми средствами поддержки времени выполнения. Отдельные элементы приведенной схемы имеют следующий смысл:
1. Возникло исключение; в данном случае это деление на ноль.
2. Управление передается обработчику исключений, в котором вычисляется выражение фильтра. Сначала вызывается функция GetExceptionCode, а затем ее возвращаемое значение используется в качестве аргумента функции Filter.
3. Функция фильтра выполняет действия, определяемые значением кода исключения.
4. В данном случае значением кода исключения является EXCEPTION_INT_DIVIDE_BY_ZERO.
5. Функция фильтра устанавливает, что должен быть выполнен код обработчика исключений, и поэтому возвращает значение EXCEPTION_EXECUTE_HANDLER.
6. Выполняется код обработчика исключений, связанного с оператором _except.
7. Управление передается за пределы блоков try и except.
Рис. 4.2.Последовательность операций при обработке исключений
Исключения, возникающие при выполнении операций над числами с плавающей точкой
Существует семь различных кодов исключений, которые могут возникать при выполнении операций с использованием данных вещественного типа. Первоначально эти исключения отключены и не могут возникать до тех пор, пока с помощью функции _controlfp для них не будет предварительно задана специальная маска, не зависящая от типа процессора. Предусмотрены отдельные исключения для ситуаций антипереполнения, переполнения, деления на ноль, неточного результата и так далее, что иллюстрируется приведенным ниже фрагментом кода. Для активизации исключений определенного типа следует отключить соответствующий бит маски.
DWORD _controlfp(DWORD new, DWORD mask)
Фактическое значение маски определяется ее текущим значением (current_mask) и двумя аргументами следующим образом:
(current_mask & ~mask) | (new & mask)
Данная функция устанавливает лишь те из битов, указанных в аргументе new, которые разрешены аргументом mask. Биты, не активизированные аргументом mask, не изменяются. Маска FP-исключений управляет также точностью, округлением и обработкой значений, соответствующих бесконечности, поэтому при активизации перечисленных исключений необходимо тщательно следить за тем, чтобы случайно не изменить эти установки.
Возвращаемым значением является фактическое значение маски. Так, при нулевых значениях обоих аргументов возвращаемым значением будет текущее значение маски (current_mask), что может быть использовано для восстановления маски, если впоследствии в этом возникнет необходимость. С другой стороны, если задать аргумент mask равным 0xFFFFFFFF, то регистр установится в new, что, например, может быть использовано для восстановления прежнего значения маски.
Обычно для того, чтобы разрешить исключения, связанные с выполнением операций над числами с плавающей точкой, в качестве аргумента mask используют константу MCW_EM, как продемонстрировано в следующем примере. Также заметьте, что при обработке FP-исключения оно должно быть сброшено путем использования функции _clearfp.
#include
DWORD FPOld, FPNew; /* Старое и новое значения маски. */
…
FPOld = _controlfp(0, 0); /* Сохранить старую маску. */
/* Указать в качестве разрешенных шесть типов исключений. */
FPNew = FPOld & ~(EM_OVERFLOW | EM_UNDERFLOW | EM_INEXACT | EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID);
/* Установить новую управляющую маску. Параметр MCW_EM объединяет шесть исключений, указанных в предыдущем операторе. */
_controlfp(FPNew, MCW_EM);
while(…) __try { /* Выполнить вычисления над числами с плавающей точкой. */
… /* На этом участке кода может возникнуть FP-исключение. */
} __except(EXCEPTION_EXECUTE_HANDLER) {
… /* Обработать FP-исключение. */
_clearfp(); /* Сбросить исключение. */
_controlfp(FPOld, 0xFFFFFFFF); /* Восстановить маску. */
}
В этом примере разрешены все возможные FP-исключения, кроме одного — EXCEPTION_FLT_STACK_CHECK, которое соответствует переполнению стека при выполнении операций над числами с плавающей точкой. Можно поступить и по-другому, разрешая отдельные исключения путем использования только выбранных масок исключений, например EM_OVERFLOW. Аналогичный код используется в программе 4.3 в контексте примера программного кода большего объема.
Читать дальше