try-except 语句

try-except 语句是 Microsoft 特定的扩展,支持 C 和 C++ 语言中的结构化异常处理

    // . . .
    __try {
        // guarded code
    }
    __except ( /* filter expression */ ) {
        // termination code
    }
    // . . .

语法

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

备注

try-except 语句是 Microsoft 对 C 和 C++ 语言的扩展。 它使目标应用程序能够在正常终止程序执行的事件发生时获得控制权。 此类事件称为“结构化异常”,简称“异常”。 处理这些异常的机制称为“结构化异常处理”(SEH)

有关相关信息,请参阅 try-finally 语句

异常可能是基于硬件的,也可能是基于软件的。 即使应用程序无法完全从硬件异常或软件异常中恢复,结构化异常处理也很有用。 SEH 可以显示错误信息和捕获应用程序的内部状态来帮助诊断问题。 这对于不易重现的间歇性问题尤其有用。

注意

结构化异常处理适用于 Win32 中的 C 和 C++ 源文件。 但是,这不是专为 C++ 设计的。 您可通过使用 C++ 异常处理来确保提高代码的可移植性。 此外,C++ 异常处理更为灵活,因此它可以处理任何类型的异常。 对于 C++ 程序,建议使用原生 C++ 异常处理:try、catch 和 throw 语句。

__try 子句后的复合语句是主体或受保护节__except 表达式也称为筛选表达式。 它的值确定了异常的处理方式。 __except 子句后的复合语句是异常处理程序。 处理程序指定在执行主体期间引发异常时要采取的操作。 执行过程如下所示:

  1. 执行受保护节。

  2. 如果在受保护节执行过程中未发生异常,则继续执行 __except 子句之后的语句。

  3. 如果在受保护节的执行过程中或受保护节调用的任何例程中发生异常,则会计算 __except 表达式。 有三种可能的值:

    • EXCEPTION_CONTINUE_EXECUTION (-1) 异常已消除。 从出现异常的点继续执行。

    • EXCEPTION_CONTINUE_SEARCH (0) 无法识别异常。 继续向上搜索堆栈查找处理程序,首先是所在的 try-except 语句,然后是具有下一个最高优先级的处理程序。

    • EXCEPTION_EXECUTE_HANDLER (1) 异常可识别。 通过执行 __except 复合语句将控制权转移到异常处理程序,然后在 __except 块后继续执行。

__except 表达式作为 C 表达式进行计算。 它仅限于单个值、条件表达式运算符或逗号运算符。 如果需要更大量的处理,表达式可调用返回上面列出的三个值之一的例程。

每个应用程序都可以有各自的异常处理程序。

跳入 __try 语句是无效的,但跳出语句是有效的。 如果在执行 try-except 语句的过程中进程被终止,则不会调用异常处理程序。

为了与以前的版本兼容,除非指定了编译器选项 /Za(禁用语言扩展),否则 _try、_except 和 _leave 与 __try__except__leave 是同义词

__leave 关键字

__leave 关键字仅在 try-except 语句的受保护节有效,其作用是跳到受保护节的末尾。 将继续执行异常处理程序后的第一个语句。

goto 语句也可以跳出受保护节,并且不会像 try-finally 语句那样降低性能。 这是因为不会发生堆栈展开。 但是,建议使用 __leave 关键字而不是 goto 语句。 原因是如果受保护节较大或复杂,则不太可能犯编程错误。

结构化异常处理内部函数

结构化异常处理提供了两个与 try-except 语句一起使用的内部函数:GetExceptionCodeGetExceptionInformation

GetExceptionCode 返回异常的代码(32 位整数)。

内部函数 GetExceptionInformation 返回指向包含异常相关附加信息的 EXCEPTION_POINTERS 结构的指针。 通过此指针,您可以访问在出现硬件异常时存在的计算机状态。 结构如下:

typedef struct _EXCEPTION_POINTERS {
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

指针类型 PEXCEPTION_RECORDPCONTEXT 在包含文件 <winnt.h> 中定义,而 _EXCEPTION_RECORD_CONTEXT 在包含文件 <excpt.h> 中定义

可以在异常处理程序中使用 GetExceptionCode。 但是,只能在异常筛选表达式中使用 GetExceptionInformation。 它指向的信息通常在堆栈上,当控制权转移到异常处理程序时不再可用。

内部函数 AbnormalTermination 在终止处理程序内可用。 如果 try-finally 语句主体按顺序终止,则返回 0。 在所有其他情况下,它将返回 1。

<excpt.h> 为这些内部函数定义了一些替换名称:

GetExceptionCode 等效于 _exception_code

GetExceptionInformation 等效于 _exception_info

AbnormalTermination 等效于 _abnormal_termination

示例

// exceptions_try_except_Statement.cpp
// Example of try-except and try-finally statements
#include <stdio.h>
#include <windows.h> // for EXCEPTION_ACCESS_VIOLATION
#include <excpt.h>

int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{
    puts("in filter.");
    if (code == EXCEPTION_ACCESS_VIOLATION)
    {
        puts("caught AV as expected.");
        return EXCEPTION_EXECUTE_HANDLER;
    }
    else
    {
        puts("didn't catch AV, unexpected.");
        return EXCEPTION_CONTINUE_SEARCH;
    };
}

int main()
{
    int* p = 0x00000000;   // pointer to NULL
    puts("hello");
    __try
    {
        puts("in try");
        __try
        {
            puts("in try");
            *p = 13;    // causes an access violation exception;
        }
        __finally
        {
            puts("in finally. termination: ");
            puts(AbnormalTermination() ? "\tabnormal" : "\tnormal");
        }
    }
    __except(filter(GetExceptionCode(), GetExceptionInformation()))
    {
        puts("in except");
    }
    puts("world");
}

输出

hello
in try
in try
in filter.
caught AV as expected.
in finally. termination:
        abnormal
in except
world

另请参阅

编写异常处理程序
Structured Exception Handling (C/C++)
关键字