未处理异常 2. 异常处理程序
本帖最后由 无符号整形 于 2016-7-4 21:41 编辑上次说好了要交大家如何私底下处理异常,今天就教。在这篇文章结束时,我会和大家一起讨论如何改编错误的strcat程序。
今天主要讲:
1.__except标识符
2.EXCEPTION_EXECUTE_HANDLER
3.EXCEPTION_CONTINUE_EXECUTION
4.EXCEPTION_CONTINUE_SEARCH
5.升级版的strcat程序
好的,让我们进入正题吧!
1.__except标识符:
__except是一种标识符,当__try块在执行时抛出了异常(注意:它不会像finally块那样不让你退出)就会被执行,它比finally块稍微复杂一点点。因为windows要求__except块必须返回一个值,而且具体返回几是有要求的。
标识符格式:
__try
{
//你认为很容易出错的代码
}
__except(/*处理的返回值,也可以理解成我们要求操作系统处理的方式*/)
{
//异常处理程序
}
注意__except关键字,任何时候创建一个__try块,后面必须跟着一个__finally块或者__except块。但是try块后面不能同时有__finally块和__except块也不能有多个__finally块或__except块。但是他们互相可以嵌套
至于后面得参数就留到后面去解释啦!
2.EXCEPTION_EXECUTE_HANDLER
这个标识符用来决定except的处理方式
EXCEPTION_EXECUTE_HANDLER就等于告诉操作系统:“我知道这个错误(错误),并预计这个异常在某种情况下会发生,同时已经写了一些代码去来处理它,让这些代码现在就执行吧!“注意:这个是__except块后面跟的那个括号了面的值,在excpt.h中被定义为1。
EXCEPTION_EXECUTE_HANDLER的使用方法:
__try
{
//你认为很容易出错的__代码
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
//异常处理程序
}
好了,让我们试着改编上次的strcat程序吧!
上次的代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
int main()
{
__try{
strcat(NULL, NULL);
}
__finally{
MessageBox(NULL, "发生了未处理异常!", "错误", MB_OK | MB_ICONERROR);
}
return 0;
}
这次我们直接把__finally换成__except(EXCEPTION_EXECUTE_HANDLER),表示系统发现错误后立即执行__except'
也就是这样
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
int main()
{
__try{
strcat(NULL, NULL);
}
__except (EXCEPTION_EXECUTE_HANDLER){
MessageBox(NULL, "发生了未处理异常!", "错误", MB_OK | MB_ICONERROR);
}
return 0;
}
编译并运行,这下子不会弹出“xxx.exe已停止工作“的对话框了。嘿嘿,倒是弹出下面的对话框
耶!我们终于可以利用SEH私底下处理错误了!太好了!
这就说明了EXCEPTION_EXECUTE_HANDLER的含义,大家看完之后记得敲代码试试哦!
3.EXCEPTION_CONTINUE_EXECUTION
这个嘛,就是让系统吧出错的语句再执行一次,一般都会导致再次发生错误,然后再次执行而死循环!
不过在某些地方,还是有用的。
下面的代码摘自《Windows核心编程》:
TCHAR g_szBuffer;
void FunclinRoosevelt1() {
int x = 0;
TCHAR *pchBuffer = NULL;
__try {
*pchBuffer = TEXT('J');
X = 5 / X;
}
__except(OilFilter1(&pchBuffer) ) {
MessageBox(NULL, TEXT("An exception occurred") , NULL , MB_OK);
}
MessageBox(NULL, TEXT("Function"), NULL, MB_OK);
}
LONG OilFilrer1(TCHAR **ppchBuffer){
if(*ppchBuffer == NULL){
*ppchBuffer = g_szBuffer;
return (EXCEPTION_CONTIUE_EXECUTION);
}
return(EXCEPTION_EXECUTE_HANDLER);
}
《Windows核心编程》的解释如下
当函数将字符'J'至置于pchBuffer所指向的内存缓冲区内是,遇到了第一个问题:很不辛,我们没有初始化pchBuffer,让他指向全局内存缓冲区g_szBuffer。因此,pchBuffer的值为NULL.。CPU会抛出一个异常,并对发生异常的__try块所对应的__except块的异常过滤程序进行求值。后者则以变量pchBuffer作为参数值调用OilFilter1。
当OilFilter1开始执行,它首先检查**ppchBuffer的值是是不是NULL,如果是,设置**ppBuffer的值,让他指向全局内存缓冲g_szBuffer。预算这次异常处理返回结果为EXCEPTION_CONTIUE_EXECUTION。系统·在看到过滤程序的返回职为EXCEPTION_CONTIUE_EXECUTION后,将程序控制控制流跳转到导致异常的那条指令,并尝试再次执行这条指令。这次,指令执行成功,'J'被置于g_szBuffer所指向缓冲区的第一个字节。
代码继续执行,将会遇到0作为除数的异常。系统再一次计算异常过滤程序表达式。这一次,OilFilter检查到**ppchBuffer的值不是NULL,于是返回EXCEPTION_EXECUTE_HANDLER,让系统执行except代码块。于是一个消息框被弹出,指明一个错误发生。
4.EXCPTION_CONTIUE_SEARCH
这个就是让系统执行上次的__try块,一般很少用,了解即可。
实例:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
int main()
{
__try{
strcat(NULL, NULL);
}
__except (EXCEPTION_CONTINUE_SEARCH){
MessageBox(NULL, "发生了未处理异常!", "错误", MB_OK | MB_ICONERROR);
}
MessageBox(NULL, "我还好呢!", "提醒", MB_OK | MB_ICONEXCLAMATION);
return 0;
}你猜会如何?就是延迟一会就停止工作
5.升级版strcat程序
我直接上代码看看大家看不看得懂
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
int main()
{
__try{
strcat(NULL, NULL);
}
__except (EXCEPTION_EXECUTE_HANDLER){
MessageBox(NULL, "拼接异常!", "错误", MB_OK | MB_ICONERROR);
}
MessageBox(NULL, "我还好呢!", "提醒", MB_OK | MB_ICONEXCLAMATION);
MessageBox(NULL, "拼接结果:NULLNULL", "结果出来了!", MB_OK | MB_ICONINFORMATION);
return 0;
}
运行结果:
其他的就要你自己总结了哟! __try __except无法在裸函数中使用= =如果我要在裸函数中设置异常处理怎么办?(SEH) 黑龍 发表于 2016-8-4 07:43
__try __except无法在裸函数中使用= =如果我要在裸函数中设置异常处理怎么办?(SEH)
不太明白你的意思 无符号整形 发表于 2016-8-4 08:14
不太明白你的意思
就是说
__try和__except都不能在有__declspec(naked)的函数中,否则不能通过编译,就是说无法通过__try和__except实现异常处理。如果我要在有__declspec(naked)的函数下实现异常处理,该怎么办? 黑龍 发表于 2016-8-4 09:50
就是说
__try和__except都不能在有__declspec(naked)的函数中,否则不能通过编译,就是说无法通过__try ...
先写个异常处理函数,然后再用call指令去调用它。 无符号整形 发表于 2016-8-4 13:39
先写个异常处理函数,然后再用call指令去调用它。
push offset @_@
push fs:
mov fs:,esp
mov eax,dr0;产生异常
call FOd
@_@:
pop fs:
add esp,4
这样方便= =
页:
[1]