结构化异常处理
结构化异常处理(Structured Exception Handling,简称SEH)是微软针对Windows程序异常处理进行的扩展,在Visual C++中,它同时支持C和C++语言。SEH不宜与标准C++异常处理和MFC异常处理混用,对于C++程序,微软建议使用标准C++的异常处理。
为了支持SEH,Visual C++中定义了四个关键字(由于这些关键字是非标准关键字,其它编译器不一定支持),用以扩展C 和C++语言:
(1)__except
(2)__finally
(3)__leave
(4)__try
其基本语法为:
__try { ...//可能导致异常的被监控代码块 } __except(filter-expression) { ...//异常处理函数 } |
或:
__try { ... } __finally { ...//终止 } |
其执行的步骤如下:
(1)__try块被执行;
(2)如果__try块没有出现异常,则执行到__except块之后;否则,执行到__except块,根据filter-expression的值决定异常处理方法:
a. filter-expression的值为EXCEPTION_CONTINUE_EXECUTION (-1)
恢复异常,从发生异常处下面开始执行,异常处理函数本身不被执行;
b. filter-expression的值为EXCEPTION_CONTINUE_SEARCH (0)
异常不被识别,拒绝捕获异常,继续搜索下一个异常处理函数;
c. filter-expression的值为EXCEPTION_EXECUTE_HANDLER (1)
异常被识别,终止异常,从异常发生处开始退栈,一路上遇到的终止函数都被执行。
看看这个例子:
//例4-1 #include "stdio.h" void main() { int* p = NULL; // 定义一个空指针 puts("SEH begin"); __try { puts("in try"); __try { puts("in try"); *p = 0; // 引发一个内存访问异常 } __finally { puts("in finally"); } } __except(puts("in filter"), 1) { puts("in except"); } puts("SEH end"); } |
程序的输出为:
SEH begin in try //执行__try块 in try //执行嵌入的__try块 in filter //执行filter-expression,返回EXCEPTION_EXECUTE_HANDLER in finally //展开嵌入的__finally in except //执行对应的__except块 SEH end //处理完毕 |
如果我们把__except(puts("in filter"), 1)改为__except(puts("in filter"), 0),程序的输出将变为:
SEH begin in try //执行__try块 in try //执行嵌入的__try块 in filter //执行filter-expression,返回EXCEPTION_CONTINUE_SEARCH in finally //展开嵌入的__finally |
程序的执行也告崩溃,弹出如图3所示的对话框。
图3 不能被正确执行的SEH |
要想这个程序能正确地执行,我们可以在第一个__try块的外面再套一个__try块和一个接收filter-expression返回值为EXCEPTION_EXECUTE_HANDLER的__except块,程序改为:
//例4-2 #include "stdio.h" void main() { int* p = NULL; // 定义一个空指针 puts("SEH begin"); __try { __try { puts("in try"); __try { puts("in try"); *p = 0; // 引发一个内存访问异常 } __finally { puts("in finally"); } } __except(puts("in filter"), 0) { puts("in except"); } } __except(puts("in filter"), 1) { puts("in except"); } puts("SEH end"); } |
程序输出:
SEH begin in try //执行__try块 in try //执行嵌入的__try块 in filter1 //执行filter-expression,返回EXCEPTION_CONTINUE_SEARCH in filter2 //执行filter-expression,返回EXCEPTION_EXECUTE_HANDLER in finally //展开嵌入的__finally in except2 //执行对应的__except块 SEH end //处理完毕 |
由此可以看出,因为第一个__except的filter-expression返回EXCEPTION_CONTINUE_SEARCH 的原因,"in except1"没有被输出。程序之所以没有崩溃,是因为最终碰到了接收EXCEPTION_EXECUTE_HANDLER的第2个__except。
SEH使用复杂的地方在于较难控制异常处理的流动方向,弄不好程序就"挂"了。如果把例4-1中的__except(puts("in filter"), 1)改为__except(puts("in filter"), -1),程序会进入一个死循环,输出:
SEH begin in try //执行__try块 in try //执行嵌入的__try块 in filter //执行filter-expression,返回EXCEPTION_CONTINUE_EXECUTION in filter in filter in filter in filter …//疯狂输出"in filter" |
最后疯狂地输出"in filter",我们把断点设置在__except(puts("in filter"), -1)语句之前,按F5会不断进入此断点。
5.各种异常处理的对比
下表给出了从各个方面对这本文所给出的Visual C++所支持的四种异常处理进行的对比:
异常处理 | 支持语言 | 是否标准 | 复杂度 | 推荐使用 |
C异常处理 | C语言 | 标准C | 简单 | 推荐 |
C++异常处理 | C++语言 | 标准C++ | 较简单 | 推荐 |
MFC异常处理 | C++语言 | 仅针对MFC程序 | 较简单 | 不推荐 |
SEH异常处理 | C和C++语言 | 仅针对Microsoft编译环境 | 较复杂 | 不推荐 |
本文所讲解的仅仅是Visual C++异常处理的初步知识,对于更深入的内容,还需要我们在不断的编程过程中去领悟和学习。
在程序设计过程中,我们不能嫌异常处理"麻烦",对可能的错误视而不见、不加考虑。因为避免了异常处理的"麻烦",将会给我们的程序带来更大的"麻烦"。而程序中包含必要的异常处理,也是对一位优秀程序员的基本要求。
http://dev.yesky.com/115/2158115_4.shtml
以下还有一些要注意的问题,从网上找来的:
cannot use __try in functions that require object unwinding
With /GX, a function with structured exception handling cannot have objects that require unwinding (destruction).
Possible solutions
Move code that requires SEH to another function.
Rewrite functions that use SEH to avoid the use of local variables and parameters that have destructors. Do not use SEH in constructors or destructors.
Compile using /GX-.