Structured Exception Handling (C/C++)

Структурированная обработка исключений (SEH) — это расширение Майкрософт для C для обработки определенных исключительных ситуаций кода, таких как ошибки оборудования, корректно. Хотя Windows и Microsoft C++ поддерживают SEH, рекомендуется использовать обработку исключений C++ стандарта ISO. Это делает код более переносимым и гибким. Однако для поддержания существующего кода или для определенных типов программ может потребоваться использовать SEH.

Для конкретной корпорации Майкрософт:

Грамматика

try-except-statement :
__try compound-statement __except ( expression ) compound-statement

try-finally-statement :
__try compound-statement __finally compound-statement

Комментарии

С помощью SEH можно гарантировать, что ресурсы, такие как блоки памяти и файлы, освобождаются правильно, если выполнение неожиданно завершается. Вы также можете справиться с конкретными проблемами ( например, нехваткой памяти), используя краткий структурированный код, который не зависит от goto инструкций или сложного тестирования кодов возврата.

try-finally Приведенные try-except в этой статье инструкции являются расширениями Майкрософт для языка C. Они поддерживают SEH, позволяя приложениям получать контроль над программой после событий, которые в иных ситуациях привели бы к завершению выполнения. Хотя обработка ошибок SEH работает с исходными файлами C++, она не была создана специально для этого языка. Если вы используете SEH в программе C++, которая компилируется с помощью /EHa или /EHsc параметра, деструкторы для локальных объектов вызываются, но другое поведение выполнения может не быть ожидаемым. Иллюстрация приведена ниже в этой статье. В большинстве случаев вместо SEH рекомендуется использовать обработку исключений C++ стандарта ISO, которую также поддерживает компилятор Microsoft C++. С помощью обработки исключений C++ можно повысить переносимость кода и обрабатывать исключения любого типа.

Если у вас есть код C, использующий SEH, его можно смешивать с кодом C++, использующим обработку исключений C++. Дополнительные сведения см. в разделе "Обработка структурированных исключений" в C++.

Существует два механизма SEH.

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

  • не распознать исключение и передать управление другим обработчикам;

  • распознать исключение, но отбросить его;

  • распознать исключение и обработать его.

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

По мере развертывания стека операционная система вызывает все обработчики завершения, которые были написаны для каждой функции. Используя обработчик завершения, вы очищаете ресурсы, которые в противном случае останутся открытыми из-за ненормального завершения. Если вы ввели критический раздел, его можно выйти из обработчика завершения. Когда программа завершит работу, вы можете выполнять другие задачи по обслуживанию, такие как закрытие и удаление временных файлов.

Дальнейшие действия

Пример

Как упоминалось ранее, деструкторы для локальных объектов вызываются, если вы используете SEH в программе C++ и компилируете его с помощью /EHa или /EHsc параметра. Однако поведение во время выполнения может не быть ожидаемым, если вы также используете исключения C++. В этом примере демонстрируются эти различия в поведении.

#include <stdio.h>
#include <Windows.h>
#include <exception>

class TestClass
{
public:
    ~TestClass()
    {
        printf("Destroying TestClass!\r\n");
    }
};

__declspec(noinline) void TestCPPEX()
{
#ifdef CPPEX
    printf("Throwing C++ exception\r\n");
    throw std::exception("");
#else
    printf("Triggering SEH exception\r\n");
    volatile int *pInt = 0x00000000;
    *pInt = 20;
#endif
}

__declspec(noinline) void TestExceptions()
{
    TestClass d;
    TestCPPEX();
}

int main()
{
    __try
    {
        TestExceptions();
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Executing SEH __except block\r\n");
    }

    return 0;
}

Если вы используете /EHsc для компиляции этого кода, но макрос CPPEX локального элемента управления тестом не определен, TestClass деструктор не запускается. Выходные данные выглядят следующим образом.

Triggering SEH exception
Executing SEH __except block

Если вы используете /EHsc для компиляции кода и CPPEX определяется с помощью /DCPPEX (чтобы возникло исключение C++), TestClass выполняется деструктор и выходные данные выглядят следующим образом:

Throwing C++ exception
Destroying TestClass!
Executing SEH __except block

/EHa При компиляции кода деструктор выполняется независимо от того, TestClass было ли создано исключение с помощью стандартного выражения C++ throw или с помощью SEH. То есть определяется ли CPPEX он или нет. Выходные данные выглядят следующим образом.

Throwing C++ exception
Destroying TestClass!
Executing SEH __except block

Дополнительные сведения см. в разделе /EH (модель обработки исключений).

КОНЕЦ Только для систем Майкрософт

См. также раздел

Обработка исключений
Ключевые слова
<exception>
Ошибки и обработка исключений
Структурированная обработка исключений (Windows)