• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            大龍的博客

            常用鏈接

            統(tǒng)計(jì)

            最新評(píng)論

            SEH的強(qiáng)大功能之一(轉(zhuǎn))

            從本篇文章開(kāi)始,將全面闡述__try,__except,__finally,__leave異常模型機(jī)制,它也即是Windows系列操作系統(tǒng)平臺(tái)上提供的SEH模型。主人公阿愚將在這里與大家分享SEH的學(xué)習(xí)過(guò)程和經(jīng)驗(yàn)總結(jié)。

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

            try-except入門(mén)

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

            //seh-test.c
            #include <stdio.h>

            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è)下劃線(xiàn)作為前綴,這樣既保持了語(yǔ)義上的一致性,另外也盡最大可能來(lái)避免了關(guān)鍵字的有可能造成名字沖突而引起的麻煩等;其次,C++異常處理模型是使用catch關(guān)鍵字來(lái)定義異常處理模塊,而SEH是采用__except關(guān)鍵字來(lái)定義。并且,catch關(guān)鍵字后面往往好像接受一個(gè)函數(shù)參數(shù)一樣,可以是各種類(lèi)型的異常數(shù)據(jù)對(duì)象;但是__except關(guān)鍵字則不同,它后面跟的卻是一個(gè)表達(dá)式(可以是各種類(lèi)型的表達(dá)式,后面會(huì)進(jìn)一步分析)。

            try-except進(jìn)階

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

            // 例程1
            // 平面的線(xiàn)性結(jié)構(gòu)
            #include <stdio.h>

            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 <stdio.h>

            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 <stdio.h>

            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");
            }

            try-except異常處理規(guī)則

              try-except異常處理規(guī)則與C++異常處理模型有相似之處,例如,它們都是向上逐級(jí)搜索恰當(dāng)?shù)漠惓L幚砟K,包括跨函數(shù)的多層嵌套try- except語(yǔ)句。但是,它們的處理規(guī)則也有另外一些很大的不同之處,例如查找匹配恰當(dāng)?shù)漠惓L幚砟K的過(guò)程,在C++異常處理模型中,它是通過(guò)異常對(duì)象的類(lèi)型來(lái)匹配;但是在try-except語(yǔ)句的異常處理規(guī)則中,則是通過(guò)__except關(guān)鍵字后面括號(hào)中的表達(dá)式的值來(lái)匹配查找正確的異常處理模塊。還是看看MSDN中怎么說(shuō)的吧!摘略如下:

            The compound statement after the __try clause is the body or guarded section. The compound statement after the __except clause is the exception handler. The handler specifies a set of actions to be taken if an exception is raised during execution of the body of the guarded section. Execution proceeds as follows:
            1. The guarded section is executed.
            2. If no exception occurs during execution of the guarded section, execution continues at the statement after the __except clause.
            3. If an exception occurs during execution of the guarded section or in any routine the guarded section calls, the __except expression is evaluated and the value determines how the exception is handled. There are three values:
            EXCEPTION_CONTINUE_EXECUTION (–1) Exception is dismissed. Continue execution at the point where the exception occurred.
            EXCEPTION_CONTINUE_SEARCH (0) Exception is not recognized. Continue to search up the stack for a handler, first for containing try-except statements, then for handlers with the next highest precedence.
            EXCEPTION_EXECUTE_HANDLER (1) Exception is recognized. Transfer control to the exception handler by executing the __except compound statement, then continue execution at the assembly instruction that was executing when the exception was raised.
            Because the __except expression is evaluated as a C expression, it is limited to a single value, the conditional-expression operator, or the comma operator. If more extensive processing is required, the expression can call a routine that returns one of the three values listed above.

              對(duì)查找匹配恰當(dāng)?shù)漠惓L幚砟K的過(guò)程等幾條規(guī)則翻譯如下:
              1. 受監(jiān)控的代碼模塊被執(zhí)行(也即__try定義的模塊代碼);
              2. 如果上面的代碼執(zhí)行過(guò)程中,沒(méi)有出現(xiàn)異常的話(huà),那么控制流將轉(zhuǎn)入到__except子句之后的代碼模塊中;
              3. 否則,如果出現(xiàn)異常的話(huà),那么控制流將進(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模塊就是正確的異常處理模塊。控制流將進(jìn)入到__except模塊中。

              上面的規(guī)則其實(shí)挺簡(jiǎn)單的,很好理解。當(dāng)然,這個(gè)規(guī)則也非常的嚴(yán)謹(jǐn),它能很好的滿(mǎn)足開(kāi)發(fā)人員的各種需求,滿(mǎn)足程序員對(duì)異常處理的分類(lèi)處理的要求,它能夠給程序員提供一個(gè)靈活的控制手段。

              其中比較特殊的就是__except關(guān)鍵字后面跟的表達(dá)式,它可以是各種類(lèi)型的表達(dá)式,例如,它可以是一個(gè)函數(shù)調(diào)用,或是一個(gè)條件表達(dá)式,或是一個(gè)逗號(hào)表達(dá)式,或干脆就是一個(gè)整型常量等等。例如代碼如下:

            // seh-test.c
            // 異常處理模塊的查找過(guò)程演示
            #include <stdio.h>

            int seh_filer()
            {
            return 0;
            }

            void test()
            {
            __try
            {
            int* p;

            puts("test()函數(shù)的try塊中");

            // 下面將導(dǎo)致一個(gè)異常
            p = 0;
            *p = 45;
            }
            // 注意,__except關(guān)鍵字后面的表達(dá)式是一個(gè)函數(shù)表達(dá)式
            // 而且這個(gè)函數(shù)將返回0,所以控制流進(jìn)入到上一層
            // 的try-except語(yǔ)句中繼續(xù)查找
            __except(seh_filer())
            {
            puts("test()函數(shù)的except塊中");
            }
            }

            void main()
            {
            puts("hello");
            __try
            {
            puts("main()函數(shù)的try塊中");

            // 注意,這個(gè)函數(shù)的調(diào)用過(guò)程中,有可能出現(xiàn)一些異常
            test();
            }
            // 注意,這個(gè)表達(dá)式是一個(gè)逗號(hào)表達(dá)式
            // 它前部分打印出一條message,后部分是
            // 一個(gè)常量,所以這個(gè)值也即為整個(gè)表達(dá)式
            // 的值,因此系統(tǒng)找到了__except定義的異
            // 常處理模塊,控制流進(jìn)入到__except模塊里面
            __except(puts("in filter"), 1)
            {
            puts("main()函數(shù)的except塊中");
            }

            puts("world");
            }

              上面的程序運(yùn)行結(jié)果如下:
              hello
              main()函數(shù)的try塊中
              test()函數(shù)的try塊中
              in filter
              main()函數(shù)的except塊中
              world
              Press any key to continue

              這種運(yùn)行結(jié)果應(yīng)該是在意料之中吧!為了對(duì)它的流程進(jìn)行更清楚的分析,下圖描述出了程序的運(yùn)行控制流轉(zhuǎn)移過(guò)程,如下。

            http://byfiles.storage.msn.com/x1pN1mp8dKYgTFQGzKRebME6105or51BGbjDrskKQ5x3cw-RNCRExH00cuzP8U6qAybuiCE9msw4yGhML-hVWfFOK8DnWPKA9WtlamUEAPnYIJs4c-bXtKEVQ

              另外,對(duì)于__except關(guān)鍵字后面表達(dá)式的值,上面的規(guī)則中已經(jīng)做了詳細(xì)規(guī)定。它們有三種值,其中如果為0,那么系統(tǒng)繼續(xù)查找;如果為1,表示系統(tǒng)已經(jīng)找到正確的異常處理模塊。其實(shí)這兩個(gè)值都很好理解,可是如果值為-1的話(huà),那么處理將比較特殊,上面也提到了,此種情況下,“異常被忽略,控制流將在異常出現(xiàn)的點(diǎn)之后,繼續(xù)恢復(fù)運(yùn)行。”實(shí)際上,這就等同于說(shuō),程序的執(zhí)行過(guò)程將不受干擾,好像異常從來(lái)沒(méi)有發(fā)生一樣??匆粋€(gè)例程吧!代碼如下:

            #include <stdio.h>

            void main()
            {
            int j, zero;

            puts("hello");
            __try
            {
            puts("main()函數(shù)的try塊中");

            zero = 0;
            j = 10;
            // 下面將導(dǎo)致一個(gè)異常
            j = 45 / zero;

            // 注意,異常出現(xiàn)后,程序控制流又恢復(fù)到了這里
            printf("這里會(huì)執(zhí)行到嗎?值有如何呢?j=%d \n", j);
            }
            // 注意,這里把zero變量賦值為1,試圖恢復(fù)錯(cuò)誤,
            // 當(dāng)控制流恢復(fù)到原來(lái)異常點(diǎn)時(shí),避免了異常的再次發(fā)生
            __except(puts("in filter"), zero = 1, -1)
            {
            puts("main()函數(shù)的except塊中");
            }

            puts("world");
            }

            上面的程序運(yùn)行結(jié)果如下:
            hello
            main()函數(shù)的try塊中
            in filter
            這里會(huì)執(zhí)行到嗎?值有如何呢?j=45
            world
            Press any key to continue

              呵呵!厲害吧!要知道C++異常處理模型可沒(méi)有這樣的能力。但是請(qǐng)注意,一般這項(xiàng)功能不能輕易采用,為什么呢?因?yàn)樗鼤?huì)導(dǎo)致不穩(wěn)定,再看下面一個(gè)示例,代碼如下:

            #include <stdio.h>

            void main()
            {
            int* p, a;

            puts("hello");
            __try
            {
            puts("main()函數(shù)的try塊中");

            // 下面將導(dǎo)致一個(gè)異常
            p = 0;
            *p = 45;

            printf("這里會(huì)執(zhí)行到嗎?值有如何呢?p=%d \n", *p);
            }
            // 注意,這里把p指針賦了一個(gè)合法的值,也即說(shuō),
            // 當(dāng)控制流恢復(fù)到原來(lái)異常點(diǎn)時(shí),異常將不會(huì)再次發(fā)生
            __except(puts("in filter"), p = &a, -1)
            {
            puts("main()函數(shù)的except塊中");
            }

            puts("world");
            }

              呵呵!大家猜猜上面的程序的運(yùn)行結(jié)果如何呢?是不是和剛才的那個(gè)例子一樣,異常也得以被恢復(fù)了。朋友們!還是親自運(yùn)行測(cè)試一把。哈哈!程序運(yùn)行結(jié)果是死了,進(jìn)行一個(gè)無(wú)限循環(huán)當(dāng)中,并且控制終端內(nèi)不斷輸出“in filter”信息。為什么會(huì)出現(xiàn)這種情況,難道MSDN中有關(guān)的闡述的有問(wèn)題嗎?或這個(gè)異常處理模型實(shí)現(xiàn)上存在BUG?NO!不是這樣的,實(shí)際上這就是由于表達(dá)式返回-1值時(shí),給程序所帶來(lái)的不穩(wěn)定性。當(dāng)然,MSDN中有關(guān)的闡述也沒(méi)有錯(cuò),那么究竟具體原因是為何呢?這是因?yàn)?,表達(dá)式返回-1值時(shí),系統(tǒng)將把控制流恢復(fù)到異常出現(xiàn)點(diǎn)之后繼續(xù)運(yùn)行。這意味著什么呢?也許大家都明白了,它這里的異?;謴?fù)點(diǎn)是基于一條機(jī)器指令級(jí)別上的。這樣就有很大的風(fēng)險(xiǎn),因?yàn)樯厦娴睦讨校^的異常恢復(fù)處理,也即p = &a語(yǔ)句,它實(shí)際上的確改變了p指針值,但是這個(gè)指針值是棧上的某個(gè)內(nèi)存區(qū)域,而真正出現(xiàn)異常時(shí),代表p指針值的很有可能是某個(gè)寄存器。呵呵!是不是挺費(fèi)解的,沒(méi)關(guān)系!還是看看調(diào)試界圖吧!如下:

            http://byfiles.storage.msn.com/x1pN1mp8dKYgTFQGzKRebME62KovOI2zIOz3rCTVXO99-ku0JJm6Gg--r6FEmfo7NKpWBwPGnL6pvfxPZ2zpd1rP8MhDhEmzvQiib6XZ1TEJqu_HREcahE28g


            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類(lèi)型的指針變量。那么EXCEPTION_POINTERS結(jié)構(gòu)如何呢?如下,

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

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

            #include <windows.h>
            #include <stdio.h>

            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

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

              最后還有一點(diǎn)需要闡述,在C++的異常處理模型中,有一個(gè)throw關(guān)鍵字,也即在受監(jiān)控的代碼中拋出一個(gè)異常,那么在SEH異常處理模型中,是不是也應(yīng)該有這樣一個(gè)類(lèi)似的關(guān)鍵字或函數(shù)呢?是的,沒(méi)錯(cuò)!SEH異常處理模型中,對(duì)異常劃分為兩大類(lèi),第一種就是上面一些例程中所見(jiàn)到的,這類(lèi)異常是系統(tǒng)異常,也被稱(chēng)為硬件異常;還有一類(lèi),就是程序中自己拋出異常,被稱(chē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í)一類(lèi)的函數(shù),這以后再詳細(xì)分析它的代碼實(shí)現(xiàn)。這里還是看一個(gè)簡(jiǎn)單例子吧!代碼如下:

            #include <windows.h>
            #include <stdio.h>

            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ù)類(lèi)型未對(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("用戶(hù)自定義的軟件異常,錯(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塊中
            用戶(hù)自定義的軟件異常,錯(cuò)誤代碼:e0000001
            except塊中
            world
            Press any key to continue

              上面的程序很簡(jiǎn)單,這里不做進(jìn)一步的分析。我們需要重點(diǎn)討論的是,在__except模塊中如何識(shí)別不同的異常,以便對(duì)異常進(jìn)行很好的分類(lèi)處理。毫無(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è)字段,如下表所示:

            http://byfiles.storage.msn.com/x1pN1mp8dKYgTFQGzKRebME6105or51BGbjDrskKQ5x3cw-RNCRExH00cuzP8U6qAybuiCE9msw4yGhML-hVWfFOK8DnWPKA9WtlamUEAPnYIJs4c-bXtKEVQ

              例如我們可以在winbase.h文件中找到EXCEPTION_ACCESS_VIOLATION的值為0 xC0000005,將這個(gè)異常代碼值拆開(kāi),來(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ò)誤,線(xiàn)程可能不能夠繼續(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èi)型,它代表存取異??砂l(fā)生在系統(tǒng)中任何地方,不是使用特定設(shè)備才發(fā)生的異常。第0位到第1 5位的值為5,表示異常錯(cuò)誤的代碼。

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

            總結(jié)

             ?。?) 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塊。

             ?。?)與C++異常模型相似,try-except模型中,查找搜索異常模塊的規(guī)則也是逐級(jí)向上進(jìn)行的。但是稍有區(qū)別的是,C++異常模型是按照異常對(duì)象的類(lèi)型來(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á)式,它可以是各種類(lèi)型的表達(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ò)誤的分類(lèi)處理。

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

              本篇文章已經(jīng)對(duì)SEH的異常處理進(jìn)行了比較全面而深入的闡述,相信大家現(xiàn)在已經(jīng)對(duì)SEH的異常處理機(jī)制胸有成竹了。但是SEH的精華僅只如此嗎?非也,朋友們!繼續(xù)到下一篇的文章中,主人公阿愚將和大家一起共同探討SEH模型的另一項(xiàng)重要的機(jī)制,那就是“有效保證資源的清除”。這對(duì)于C程序可太重要了,因?yàn)樵贑++程序中,至少還有對(duì)象的析構(gòu)函數(shù)來(lái)保證資源的有效清除,避免資源泄漏,但C語(yǔ)言中則沒(méi)有一個(gè)有效的機(jī)制,來(lái)完成此等艱巨的任務(wù)。呵呵!SEH 雪中送炭,它提供了完美的解決方案,所以千萬(wàn)不要錯(cuò)過(guò),一起去看看吧!Let’s go!

            posted on 2008-01-25 19:30 大龍 閱讀(785) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            精品久久久久久久无码| 亚洲精品午夜国产VA久久成人| 91精品婷婷国产综合久久| 国产成人无码精品久久久免费 | AV无码久久久久不卡网站下载| 久久免费视频观看| 国内精品伊人久久久影院| 国内精品久久久人妻中文字幕| 日本久久中文字幕| 国产精品久久亚洲不卡动漫| 亚洲一区精品伊人久久伊人| 精品国产一区二区三区久久| 无码八A片人妻少妇久久| 国产精品日韩欧美久久综合| 成人久久免费网站| 久久亚洲av无码精品浪潮| 久久精品国产亚洲综合色| 国产成人精品综合久久久| 久久精品国产99久久久香蕉 | 久久综合九色欧美综合狠狠| 狠狠色丁香久久婷婷综合五月| 久久无码一区二区三区少妇| 久久精品国产久精国产| 久久丫精品国产亚洲av不卡| 亚洲国产成人乱码精品女人久久久不卡 | 亚洲精品美女久久777777| 久久九九久精品国产免费直播| 欧美日韩中文字幕久久伊人| 久久久久久久亚洲Av无码| 国内精品人妻无码久久久影院导航 | 久久狠狠高潮亚洲精品 | 国产一级做a爰片久久毛片| 国产亚洲美女精品久久久2020| 日本高清无卡码一区二区久久| 国产福利电影一区二区三区,免费久久久久久久精 | 老色鬼久久亚洲AV综合| 亚洲精品高清一二区久久| 热99re久久国超精品首页| 潮喷大喷水系列无码久久精品| 亚洲国产精品无码成人片久久| 婷婷五月深深久久精品|