结构化异常处理 (C/C++)

尽管 Windows 和 Visual C++ 支持结构化异常处理 (SEH),建议您使用 ISO C++ 标准异常处理,因为它使代码更具可移植的灵活。 但是,现有代码或特定类型的程序,可能仍然必须使用 SEH。

语法

try-except-statement :

__try compound-statement

__except ( expression ) compound-statement

备注

用 SEH,如果执行意外终止,可以确保诸如内存块和文件资源是正确的。 也可以处理特定的问题,例如,内存不足,当使用不依赖于 goto 语句或返回代码精心设计的测试结构简洁的代码。

本文中引用的 try-except和try-finally是基于对 C 语言的扩展。 它们支持SEH通过使应用程序去获得程序的控制,否则将终止执行活动。 虽然SEH使用 C++ 源文件,它不是对 C++ 专门设计的。 如果用 /EH 选项来在C++程序中SEH和某些修改符一起使用,那么本地对象的析构函数将被调用,但其他执行行为可能不是你所期望的。(对于图,请参见本文后面的 示例。)在大多数情况下,建议使用Visual C++ 支持的基于标准 C++ 异常处理 而不是SEH。 使用 C++ 异常处理,可以确保代码具有更强的可移植性,因此,可以用任何类型的异常处理。

如果 C 模块中使用了SEH,可以 C++ 异常处理的 C++ 模块混合使用。 有关信息,请参见异常处理差异

有两种SEH结构:

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

  • 不能识别异常和其他处理程序。

  • 异常被识别出来,但被驳回。

  • 识别和处理该异常。

该函数发生异常时,识别该异常的异常处理程序可能不在运行的函数中。 在某些情况下,它可能位于函数堆栈上更高层的地方。 当前运行的函数,其他所有在堆栈帧上的函数都被终止。 在此过程中,堆栈 “展开”:即,终止函数的局部变量从堆栈中清除,除非它们是 static。

在它展开堆栈时,操作系统调用你写的每个处理函数终止的函数。 使用终止处理,可以清除资源,否则将会因异常终止而继续开启。 如果输入了临界区,可以在终止处理程序中退出。 如果该程序将关闭,可以执行其他管理任务如关闭和移除临时文件。

有关更多信息,请参见:

示例

如上文所述,如果你在C++程序中使用了SEH,并且用 /EH 选项用某种编辑器 ,如 /EHsc/EHa 本地对象的析构函数将被调用。 但是,行为在执行时可能不是预期无论是否同时使用了 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 不执行析构函数,并输出如下所示:

  

如果使用 /EHsc 编译代码,并使用 /DCPPEX 定义 CPPEX (以便 C++ 异常的抛出), TestClass 析构函数执行和输出如下所示:

  

如果使用 /EHa 编译代码,TestClass 析构函数执行不论是否有异常发生使用 std::throw 或使用SEH触发异常 (不论是否定义CPPEX )。 输出如下所示:

  

有关详细信息,请参阅/EH(异常处理模型)

请参见

参考

Visual C++ 中的异常处理

C++ 关键字

<exception>

概念

错误和异常处理(现代 C++)

其他资源

结构化异常处理(Windows)