国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
[轉(zhuǎn)]SEH(結(jié)構(gòu)化異常處理)_Lsz's Blog
2009-05-22 22:41

其實(shí)我對(duì)于SEH不甚了解,可惜因?yàn)榘俣鹊脑?,之前那篇SEH的拙文污染了很多大牛們的眼睛,這里補(bǔ)一篇。。。轉(zhuǎn)的。。

作者:wangxvfeng101

出處:http://hi.baidu.com/wangxvfeng101/blog/item/330699fedec079395d600885.html

1、當(dāng)執(zhí)行try...except之間的語(yǔ)句序列沒(méi)有發(fā)生異常時(shí),則忽略異常處理部分的語(yǔ)句,程序直接轉(zhuǎn)移try...except..finally后面的語(yǔ)句處執(zhí)行;
2、Except括起來(lái)的語(yǔ)句,則只有在產(chǎn)生異常的情況下會(huì)被執(zhí)行,其他情況一概不執(zhí)行的。
3、Finally括起來(lái)的語(yǔ)句是鐵定會(huì)被執(zhí)行的,無(wú)論是否有異常產(chǎn)生;


try...except形式指定一個(gè)或多個(gè)異常處理器(異常子句). 當(dāng)在try子句中沒(méi)有異常發(fā)生時(shí), 異常處理器將不被執(zhí)行. 當(dāng)在try子句中有異常發(fā)生時(shí), 就會(huì)開始搜索異常處理器.它會(huì)按順序搜索直到第一個(gè)匹配的處理器找到為止. 如果存在一個(gè)沒(méi)有指定異常的except語(yǔ)句, 它必須放在最后, 它會(huì)匹配任何異常.當(dāng)一個(gè)except匹配, 相應(yīng)表達(dá)式會(huì)被計(jì)算. 如果結(jié)果對(duì)象與該異常"兼容", 那么該子句就匹配了這個(gè)異常.如果這個(gè)對(duì)象是標(biāo)識(shí)這個(gè)異常的對(duì)象, 或(異常類)是該異常的基類, 或者它是一個(gè)包括與該異常兼容的對(duì)象的元組就稱為這個(gè)對(duì)象是兼容的. 注意對(duì)象的標(biāo)識(shí)必須匹配, 那就是說(shuō), 它必須是相同的對(duì)象, 不僅是具有相同值的對(duì)象.


try...finally形式指定一個(gè)清除處理器. 在執(zhí)行try語(yǔ)句塊沒(méi)有異常發(fā)生時(shí), finally子句被執(zhí)行.在異常引發(fā)時(shí), 該異常就被臨時(shí)保存起來(lái), finally也被執(zhí)行, 然后暫存的異常被重新引發(fā).如果執(zhí)行finally子句時(shí)引發(fā)了另一個(gè)異?;驁?zhí)行了return或break語(yǔ)句, 就會(huì)拋棄保存的異常,在finally子句中的continue語(yǔ)句是非法的(這么做的原因是當(dāng)前實(shí)現(xiàn)的原因 ---- 這個(gè)限制可能也會(huì)保留下去)在執(zhí)行finally子句時(shí)異常信息是無(wú)效的.

SEH有兩項(xiàng)非常強(qiáng)大的功能。當(dāng)然,首先是異常處理模型了,因此,這篇文章首先深入闡述SEH提供的異常處理模型。另外,SEH還有一個(gè)特別強(qiáng)大的功能,這將在下一篇文章中進(jìn)行詳細(xì)介紹。

try-except入門

SEH的異常處理模型主要由try-except語(yǔ)句來(lái)完成,它與標(biāo)準(zhǔn)C++所定義的異常處理模型非常類似,也都是可以定義出受監(jiān)控的代碼模塊,以及定義異常處理模塊等。還是老辦法,看一個(gè)例子先,代碼如下:

//seh-test.c
#include


void main()
{
puts("hello");
// 定義受監(jiān)控的代碼模塊
__try
{
puts("in try");
}
//定義異常處理模塊
__except(1)
{
puts("in except");
}
puts("world");
}


  呵呵!是不是很簡(jiǎn)單,而且與C++異常處理模型很相似。當(dāng)然,為了與C++異常處理模型相區(qū)別,VC編譯器對(duì)關(guān)鍵字做了少許變動(dòng)。首先是在每個(gè) 關(guān)鍵字加上兩個(gè)下劃線作為前綴,這樣既保持了語(yǔ)義上的一致性,另外也盡最大可能來(lái)避免了關(guān)鍵字的有可能造成名字沖突而引起的麻煩等;其次,C++異常處理 模型是使用catch關(guān)鍵字來(lái)定義異常處理模塊,而SEH是采用__except關(guān)鍵字來(lái)定義。并且,catch關(guān)鍵字后面往往好像接受一個(gè)函數(shù)參數(shù)一 樣,可以是各種類型的異常數(shù)據(jù)對(duì)象;但是__except關(guān)鍵字則不同,它后面跟的卻是一個(gè)表達(dá)式(可以是各種類型的表達(dá)式,后面會(huì)進(jìn)一步分析)。

try-except進(jìn)階

與C++異常處理模型很相似,在一個(gè)函數(shù)中,可以有多個(gè)try-except語(yǔ)句。它們可以是一個(gè)平面的線性結(jié)構(gòu),也可以是分層的嵌套結(jié)構(gòu)。例程代碼如下:


// 例程1
// 平面的線性結(jié)構(gòu)
#include


void main()
{
puts("hello");
__try
{
puts("in try");
}
__except(1)
{
puts("in except");
}


// 又一個(gè)try-except語(yǔ)句
__try
{
puts("in try");
}
__except(1)
{
puts("in except");
}


puts("world");
}



// 例程2
// 分層的嵌套結(jié)構(gòu)
#include


void main()
{
puts("hello");
__try
{
puts("in try");
// 又一個(gè)try-except語(yǔ)句
__try
{
puts("in try");
}
__except(1)
{
puts("in except");
}
}
__except(1)
{
puts("in except");
}


puts("world");
}



// 例程3
// 分層的嵌套在__except模塊中
#include


void main()
{
puts("hello");
__try
{
puts("in try");
}
__except(1)
{
// 又一個(gè)try-except語(yǔ)句
__try
{
puts("in try");
}
__except(1)
{
puts("in except");
}


puts("in except");
}


puts("world");
}
1. 受監(jiān)控的代碼模塊被執(zhí)行(也即__try定義的模塊代碼);
2. 如果上面的代碼執(zhí)行過(guò)程中,沒(méi)有出現(xiàn)異常的話,那么控制流將轉(zhuǎn)入到__except子句之后的代碼模塊中;
3. 否則,如果出現(xiàn)異常的話,那么控制流將進(jìn)入到__except后面的表達(dá)式中,也即首先計(jì)算這個(gè)表達(dá)式的值,之后再根據(jù)這個(gè)值,來(lái)決定做出相應(yīng)的處理。這個(gè)值有三種情況,如下:
EXCEPTION_CONTINUE_EXECUTION (–1) 異常被忽略,控制流將在異常出現(xiàn)的點(diǎn)之后,繼續(xù)恢復(fù)運(yùn)行。
EXCEPTION_CONTINUE_SEARCH (0) 異常不被識(shí)別,也即當(dāng)前的這個(gè)__except模塊不是這個(gè)異常錯(cuò)誤所對(duì)應(yīng)的正確的異常處理模塊。系統(tǒng)將繼續(xù)到上一層的try-except域中繼續(xù)查找一個(gè)恰當(dāng)?shù)腳_except模塊。
EXCEPTION_EXECUTE_HANDLER (1) 異常已經(jīng)被識(shí)別,也即當(dāng)前的這個(gè)異常錯(cuò)誤,系統(tǒng)已經(jīng)找到了并能夠確認(rèn),這個(gè)__except模塊就是正確的異常處理模塊??刂屏鲗⑦M(jìn)入到__except模塊中。


try-except深入

  上面的內(nèi)容中已經(jīng)對(duì)try-except進(jìn)行了全面的了解,但是有一點(diǎn)還沒(méi)有闡述到。那就是如何在__except模塊中獲得異常 錯(cuò)誤的相關(guān)信息,這非常關(guān)鍵,它實(shí)際上是進(jìn)行異常錯(cuò)誤處理的前提,也是對(duì)異常進(jìn)行分層分級(jí)別處理的前提。可想而知,如果沒(méi)有這些起碼的信息,異常處理如何 進(jìn)行?因此獲取異常信息非常的關(guān)鍵。Windows提供了兩個(gè)API函數(shù),如下:


LPEXCEPTION_POINTERS GetExceptionInformation(VOID);
DWORD GetExceptionCode(VOID);

其中GetExceptionCode()返回錯(cuò)誤代碼,而GetExceptionInformation()返回更全面的信息,看它函數(shù)的聲明, 返回了一個(gè)LPEXCEPTION_POINTERS類型的指針變量。那么EXCEPTION_POINTERS結(jié)構(gòu)如何呢?如下,


typedef struct _EXCEPTION_POINTERS { // exp
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS;


  呵呵!仔細(xì)瞅瞅,這是不是和上一篇文章中,用戶程序所注冊(cè)的異常處理的回調(diào)函數(shù)的兩個(gè)參數(shù)類型一樣。是的,的確沒(méi)錯(cuò)!其中 EXCEPTION_RECORD類型,它記錄了一些與異常相關(guān)的信息;而CONTEXT數(shù)據(jù)結(jié)構(gòu)體中記錄了異常發(fā)生時(shí),線程當(dāng)時(shí)的上下文環(huán)境,主要包括 寄存器的值。因此有了這些信息,__except模塊便可以對(duì)異常錯(cuò)誤進(jìn)行很好的分類和恢復(fù)處理。不過(guò)特別需要注意的是,這兩個(gè)函數(shù)只能是在 __except后面的括號(hào)中的表達(dá)式作用域內(nèi)有效,否則結(jié)果可能沒(méi)有保證(至于為什么,在后面深入分析異常模型的實(shí)現(xiàn)時(shí)候,再做詳細(xì)闡述)??匆粋€(gè)例程 吧!代碼如下:


#include
#include


int exception_access_violation_filter(LPEXCEPTION_POINTERS p_exinfo)
{
if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
printf("存儲(chǔ)保護(hù)異常\n");
return 1;
}
else return 0;
}


int exception_int_divide_by_zero_filter(LPEXCEPTION_POINTERS p_exinfo)
{
if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
{
printf("被0除異常\n");
return 1;
}
else return 0;
}


void main()
{
puts("hello");
__try
{
__try
{
int* p;


// 下面將導(dǎo)致一個(gè)異常
p = 0;
*p = 45;
}
// 注意,__except模塊捕獲一個(gè)存儲(chǔ)保護(hù)異常
__except(exception_access_violation_filter(GetExceptionInformation()))
{
puts("內(nèi)層的except塊中");
}
}
// 注意,__except模塊捕獲一個(gè)被0除異常
__except(exception_int_divide_by_zero_filter(GetExceptionInformation()))
{
puts("外層的except塊中");
}


puts("world");
}


上面的程序運(yùn)行結(jié)果如下:
hello
存儲(chǔ)保護(hù)異常
內(nèi)層的except塊中
world
Press any key to continue


  呵呵!感覺不錯(cuò),大家可以在上面的程序基礎(chǔ)之上改動(dòng)一下,讓它拋出一個(gè)被0除異常,看程序的運(yùn)行結(jié)果是不是如預(yù)期那樣。

最后還有一點(diǎn)需要闡述,在C++的異常處理模型中,有一個(gè)throw關(guān)鍵字,也即在受監(jiān)控的代碼中拋出一個(gè)異常,那么在SEH異常處理模型中,是不是 也應(yīng)該有這樣一個(gè)類似的關(guān)鍵字或函數(shù)呢?是的,沒(méi)錯(cuò)!SEH異常處理模型中,對(duì)異常劃分為兩大類,第一種就是上面一些例程中所見到的,這類異常是系統(tǒng)異 常,也被稱為硬件異常;還有一類,就是程序中自己拋出異常,被稱為軟件異常。怎么拋出呢?還是Windows提供了的API函數(shù),它的聲明如下:


VOID RaiseException(
DWORD dwExceptionCode, // exception code
DWORD dwExceptionFlags, // continuable exception flag
DWORD nNumberOfArguments, // number of arguments in array
CONST DWORD *lpArguments // address of array of arguments
);


  很簡(jiǎn)單吧!實(shí)際上,在C++的異常處理模型中的throw關(guān)鍵字,最終也是對(duì)RaiseException()函數(shù)的調(diào)用,也即是 說(shuō),throw是RaiseException的上層封裝的更高級(jí)一類的函數(shù),這以后再詳細(xì)分析它的代碼實(shí)現(xiàn)。這里還是看一個(gè)簡(jiǎn)單例子吧!代碼如下:


#include
#include


int seh_filer(int code)
{
switch(code)
{
case EXCEPTION_ACCESS_VIOLATION :
printf("存儲(chǔ)保護(hù)異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_DATATYPE_MISALIGNMENT :
printf("數(shù)據(jù)類型未對(duì)齊異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_BREAKPOINT :
printf("中斷異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_SINGLE_STEP :
printf("單步中斷異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
printf("數(shù)組越界異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_FLT_DENORMAL_OPERAND :
case EXCEPTION_FLT_DIVIDE_BY_ZERO :
case EXCEPTION_FLT_INEXACT_RESULT :
case EXCEPTION_FLT_INVALID_OPERATION :
case EXCEPTION_FLT_OVERFLOW :
case EXCEPTION_FLT_STACK_CHECK :
case EXCEPTION_FLT_UNDERFLOW :
printf("浮點(diǎn)數(shù)計(jì)算異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO :
printf("被0除異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_INT_OVERFLOW :
printf("數(shù)據(jù)溢出異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_IN_PAGE_ERROR :
printf("頁(yè)錯(cuò)誤異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_ILLEGAL_INSTRUCTION :
printf("非法指令異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_STACK_OVERFLOW :
printf("堆棧溢出異常,錯(cuò)誤代碼:%x\n", code);
break;
case EXCEPTION_INVALID_HANDLE :
printf("無(wú)效句病異常,錯(cuò)誤代碼:%x\n", code);
break;
default :
if(code & (1<<29))
printf("用戶自定義的軟件異常,錯(cuò)誤代碼:%x\n", code);
else
printf("其它異常,錯(cuò)誤代碼:%x\n", code);
break;
}

return 1;
}


void main()
{
puts("hello");
__try
{
puts("try塊中");


// 注意,主動(dòng)拋出一個(gè)軟異常
RaiseException(0xE0000001, 0, 0, 0);
}
__except(seh_filer(GetExceptionCode()))
{
puts("except塊中");
}


puts("world");
}


上面的程序運(yùn)行結(jié)果如下:
hello
try塊中
用戶自定義的軟件異常,錯(cuò)誤代碼:e0000001
except塊中
world
Press any key to continue


  上面的程序很簡(jiǎn)單,這里不做進(jìn)一步的分析。我們需要重點(diǎn)討論的是,在__except模塊中如何識(shí)別不同的異常,以便對(duì)異常進(jìn)行很好的分類處 理。毫無(wú)疑問(wèn),它當(dāng)然是通過(guò)GetExceptionCode()或GetExceptionInformation ()函數(shù)來(lái)獲取當(dāng)前的異常錯(cuò)誤代碼,實(shí)際也即是DwExceptionCode字段。異常錯(cuò)誤代碼在winError.h文件中定義,它遵循 Windows系統(tǒng)下統(tǒng)一的錯(cuò)誤代碼的規(guī)則。每個(gè)DWORD被劃分幾個(gè)字段

例如我們可以在winbase.h文件中找到EXCEPTION_ACCESS_VIOLATION的值為0 xC0000005,將這個(gè)異常代碼值拆開,來(lái)分析看看它的各個(gè)bit位字段的涵義。
C 0 0 0 0 0 0 5 (十六進(jìn)制)
1100 0000 0000 0000 0000 0000 0000 0101 (二進(jìn)制)
第3 0位和第3 1位都是1,表示該異常是一個(gè)嚴(yán)重的錯(cuò)誤,線程可能不能夠繼續(xù)往下運(yùn)行,必須要及時(shí)處理恢復(fù)這個(gè)異常。第2 9位是0,表示系統(tǒng)中已經(jīng)定義了異常代碼。第2 8位是0,留待后用。第1 6 位至2 7位是0,表示是FACILITY_NULL設(shè)備類型,它代表存取異??砂l(fā)生在系統(tǒng)中任何地方,不是使用特定設(shè)備才發(fā)生的異常。第0位到第1 5位的值為5,表示異常錯(cuò)誤的代碼。

如果程序員在程序代碼中,計(jì)劃拋出一些自定義類型的異常,必須要規(guī)劃設(shè)計(jì)好自己的異常類型的劃分,按照上面的規(guī)則來(lái)填充異常代碼的各個(gè)字段值,如上面示例程序中拋出一個(gè)異常代碼為0xE0000001軟件異常。

總結(jié)

(1) C++異常模型用try-catch語(yǔ)法定義,而SEH異常模型則用try-except語(yǔ)法;

(2) 與C++異常模型相似,try-except也支持多層的try-except嵌套。

(3)與C++異常模型不同的是,try-except模型中,一個(gè)try塊只能是有一個(gè)except塊;而C++異常模型中,一個(gè)try塊可以有多個(gè)catch塊。

(4)與C++異常模型相似,try-except模型中,查找搜索異常模塊的規(guī)則也是逐級(jí)向上進(jìn)行的。但是稍有區(qū)別的是,C++異常模型是按照異常 對(duì)象的類型來(lái)進(jìn)行匹配查找的;而try-except模型則不同,它通過(guò)一個(gè)表達(dá)式的值來(lái)進(jìn)行判斷。如果表達(dá)式的值為 1(EXCEPTION_EXECUTE_HANDLER),表示找到了異常處理模塊;如果值為 0(EXCEPTION_CONTINUE_SEARCH),表示繼續(xù)向上一層的try-except域中繼續(xù)查找其它可能匹配的異常處理模塊;如果值為 -1(EXCEPTION_CONTINUE_EXECUTION),表示忽略這個(gè)異常,注意這個(gè)值一般很少用,因?yàn)樗苋菀讓?dǎo)致程序難以預(yù)測(cè)的結(jié)果,例 如,死循環(huán),甚至導(dǎo)致程序的崩潰等。

(5) __except關(guān)鍵字后面跟的表達(dá)式,它可以是各種類型的表達(dá)式,例如,它可以是一個(gè)函數(shù)調(diào)用,或是一個(gè)條件表達(dá)式,或是一個(gè)逗號(hào)表達(dá)式,或干脆就是一 個(gè)整型常量等等。最常用的是一個(gè)函數(shù)表達(dá)式,并且通過(guò)利用GetExceptionCode()或GetExceptionInformation ()函數(shù)來(lái)獲取當(dāng)前的異常錯(cuò)誤信息,便于程序員有效控制異常錯(cuò)誤的分類處理。

(6) SEH異常處理模型中,異常被劃分為兩大類:系統(tǒng)異常和軟件異常。其中軟件異常通過(guò)RaiseException()函數(shù)拋出。RaiseException()函數(shù)的作用類似于C++異常模型中的throw語(yǔ)句。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
C++及Windows異常處理(try,catch;
Visual C++中的異常處理淺析
19. 異常處理
python except 用法
深入理解Python異常處理:從基礎(chǔ)到高級(jí)
python3 異常處理try、raise
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服