Structured Exception Handling (C/C++)

结构化异常处理 (SEH) 是 Microsoft 对 C 和 C++ 语言的一个扩展,用于适当地处理某些异常代码情况,例如硬件故障。 尽管 Windows 和 Microsoft C++ 支持 SEH,但我们建议在 C++ 代码中使用 ISO 标准 C++ 异常处理。 它提高了代码的可移植性和灵活性。 但是,为了维护现有代码,或者对于特定类型的程序,你仍可能必须使用 SEH。

Microsoft 专用:

语法

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

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

备注

使用 SEH,你可以确保在执行意外终止时,可以正确地释放资源(如内存块和文件)。 你还可以处理特定问题,例如,没有足够的内存,方法是使用简洁的结构化代码,该代码不依赖于 goto 语句或返回代码的详尽测试。

这篇文章中引用的 try-excepttry-finally 语句是 C 和 C++ 语言的 Microsoft 扩展。 它们通过使应用程序可以在事件后获得对程序的控制(否则事件将终止执行)来支持 SEH。 尽管 SEH 使用 C++ 源文件,但它并不是专为 C++ 设计的。 如果通过使用 /EHa/EHsc 选项,在编译的 C++ 程序中使用 SEH,则会调用本地对象的析构函数,但其他执行行为可能不是你所预期的。 有关说明,请参阅本文后面的示例。 在大多数情况下,建议不要使用 ISO 标准 C++ 异常处理。 使用 C++ 异常处理可以确保你的代码更具可移植性,并且你可以处理任何类型的异常。

如果你有使用 SEH 的 C 代码,可以将它与使用 C++ 异常处理的 C++ 代码混合使用。 有关信息,请参阅在 C++ 中处理结构化异常

有两种 SEH 机制:

这两种类型的处理程序是不同的,但会通过称为“展开堆栈”的过程紧密关联。 发生结构化异常时,Windows 将查找当前处于活动状态的最新安装的异常处理程序。 该处理程序可以执行以下三个操作之一:

  • 无法识别异常并将控件传递给其他处理程序 (EXCEPTION_CONTINUE_SEARCH)。

  • 识别异常,但将其消除 (EXCEPTION_CONTINUE_EXECUTION)。

  • 识别异常并处理它 (EXCEPTION_EXECUTE_HANDLER)。

识别异常的异常处理程序可能不在异常发生时正在运行的函数中。 它可能在堆栈上高得多的函数中。 当前正在运行的函数和堆栈帧上的所有其他函数都将终止。 在此过程中,堆栈会展开。 也就是说,已终止函数的局部非静态变量会从堆栈中清除。

当它展开堆栈时,操作系统将调用你为每个函数编写的任何终止处理程序。 通过使用终止处理程序清理资源,否则资源将由于异常终止而保持打开状态。 如果你已输入了关键部分,可以在终止处理程序中退出它。 程序将要关闭时,你可以执行其他维护任务,如关闭和删除临时文件。

后续步骤

示例

正如前文所述,如果你在 C++ 程序中使用 SEH,并通过使用 /EHa/EHsc 选项对其进行编译,则会调用本地对象的析构函数。 但是,如果你也正在使用 C++ 异常,则执行过程中的行为可能不是你所预期的。 此示例演示了这些行为差异。

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

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

__declspec(noinline) void TestCPPEX()
{
#ifdef CPPEX
    printf("Throwing C++ exception\n");
    throw std::exception("");
#else
    printf("Triggering SEH exception\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\n");
    }

    return 0;
}

如果你使用 /EHsc 来编译此代码,但未定义本地测试控件宏 CPPEX,则不运行 TestClass 析构函数。 输出如下所示:

Triggering SEH exception
Executing SEH __except block

如果你使用 /EHsc 来编译代码,且使用 /DCPPEX 定义了 CPPEX(以致引发 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(异常处理模型)

结束 Microsoft 专用

另请参阅

异常处理
关键字
<exception>
错误和异常处理
结构化异常处理 (Windows)