• <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)計

            最新評論

            SEH的強大功能之二(轉(zhuǎn))

            上一篇文章講述了SEH的異常處理機制,也即try-except模型的使用規(guī)則。本篇文章繼續(xù)探討SEH另外一項很重要的機制,那就是“有效保證資源的清除”,其實這才是SEH設計上最為精華的一個東東,對于C程序而言,它貢獻簡直是太大了。

              SEH的這項機制被稱為結(jié)束處理(Termination Handling),它是通過try-finally語句來實現(xiàn)的,下面開始討論吧!

            try-finally的作用


              對于try-finally的作用,還是先看看MSDN中怎么說的吧!摘略如下:

            The try-finally statement is a Microsoft extension to the C and C++ languages that enables 32-bit target applications to guarantee execution of cleanup code when execution of a block of code is interrupted. Cleanup consists of such tasks as deallocating memory, closing files, and releasing file handles. The try-finally statement is especially useful for routines that have several places where a check is made for an error that could cause premature return from the routine.

              上面的這段話的內(nèi)容翻譯如下:

              try-finally語句是Microsoft對C和C++語言的擴展,它能使32位的目標程序在異常出現(xiàn)時,有效保證一些資源能夠被及時清除,這些資源的清除任務可以包括例如內(nèi)存的釋放,文件的關(guān)閉,文件句柄的釋放等等。try-finally語句特別適合這樣的情況下使用,例如一個例程(函數(shù))中,有幾個地方需要檢測一個錯誤,并且在錯誤出現(xiàn)時,函數(shù)可能提前返回。

            try-finally的語法規(guī)則

               上面描述try-finally機制的有關(guān)作用時,也許一時我們還難以全面理解,不過沒關(guān)系,這里還是先看一下try-finally的語法規(guī)則吧!其實它很簡單,示例代碼如下:

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

            void main()
            {
            puts("hello");
            __try
            {
            puts("__try塊中");
            }
            // 注意,這里不是__except塊,而是__finally取代
            __finally
            {
            puts("__finally塊中");
            }

            puts("world");
            }

            上面的程序運行結(jié)果如下:
            hello
            __try塊中
            __finally塊中
            world
            Press any key to continue

              try-finally語句的語法與try-except很類似,稍有不同的是,__finally后面沒有一個表達式,這是因為try- finally語句的作用不是用于異常處理,所以它不需要一個表達式來判斷當前異常錯誤的種類。另外,與try-except語句類似,try- finally也可以是多層嵌套的,并且一個函數(shù)內(nèi)可以有多個try-finally語句,不管它是嵌套的,或是平行的。當然,try-finally多層嵌套也可以是跨函數(shù)的。這里不一一列出示例,大家可以自己測試一番。
            另外,對于上面示例程序的運行結(jié)果,是不是覺得有點意料之外呢?因為 __finally塊中的put(“__finally塊中”)語句也被執(zhí)行了。是的,沒錯!這就是try-finally語句最具有魔幻能力的地方,即 “不管在何種情況下,在離開當前的作用域時,finally塊區(qū)域內(nèi)的代碼都將會被執(zhí)行到”。呵呵!這的確是很厲害吧!為了驗證這條規(guī)則,下面來看一個更典型示例,代碼如下:

            #include <stdio.h>

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

            // 注意,下面return語句直接讓函數(shù)返回了
            return;
            }
            __finally
            {
            puts("__finally塊中");
            }

            puts("world");
            }

            上面的程序運行結(jié)果如下:
            hello
            __try塊中
            __finally塊中
            Press any key to continue

              上面的程序運行結(jié)果是不是有點意思。在__try塊區(qū)域中,有一條return語句讓函數(shù)直接返回了,所以后面的put(“world”)語句沒有被執(zhí)行到,這是很容易被理解的。但是請注意,__finally塊區(qū)域中的代碼也將會被予以執(zhí)行過了,這是不是進一步驗證了上面了那條規(guī)則,呵呵!阿愚深有感觸的想:“__finally的特性真的很像對象的析構(gòu)函數(shù)”,朋友們覺得如何呢?

               另外,大家也許還特別關(guān)心的是,goto語句是不是有可能破壞上面這條規(guī)則呢?因為在C語言中,goto語句一般直接對應一條jmp跳轉(zhuǎn)指令,所以如果真的如此的話,那么goto語句很容易破壞上面這條規(guī)則。還是看一個具體的例子吧!

            #include <stdio.h>

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

            // 跳轉(zhuǎn)指令
            goto RETURN;
            }
            __finally
            {
            puts("__finally塊中");
            }

            RETURN:
            puts("world");
            }

            上面的程序運行結(jié)果如下:
            hello
            __try塊中
            __finally塊中
            world
            Press any key to continue

              呵呵!即便上面的示例程序中,goto語句跳過了__finally塊,但是__finally塊區(qū)域中的代碼還是被予以執(zhí)行了。當然,大家也許很關(guān)心這到底是為什么?為什么try-finally語句具有如此神奇的功能?這里不打算深入闡述,在后面闡述SEH實現(xiàn)的時候會詳細分析到。這里朋友們只牢記一點,“不管是順序的線性執(zhí)行,還是return語句或goto語句無條件跳轉(zhuǎn)等情
            況下,一旦執(zhí)行流在離開當前的作用域時,finally塊區(qū)域內(nèi)的代碼必將會被執(zhí)行”

            try-finally塊中的異常


              上面只列舉了return語句和goto語句的情況下,但是如果程序中出現(xiàn)異常的話,那么finally塊區(qū)域內(nèi)的代碼還會被執(zhí)行嗎?上面所講到的那條規(guī)則仍然正確嗎?還是看看示例,代碼如下:

            #include <stdio.h>

            void test()
            {
            puts("hello");
            __try
            {
            int* p;
            puts("__try塊中");

            // 下面拋出一個異常
            p = 0;
            *p = 25;
            }
            __finally
            {
            // 這里會被執(zhí)行嗎
            puts("__finally塊中");
            }

            puts("world");
            }

            void main()
            {
            __try
            {
            test();
            }
            __except(1)
            {
            puts("__except塊中");
            }
            }

            上面的程序運行結(jié)果如下:
            hello
            __try塊中
            __finally塊中
            __except塊中
            Press any key to continue

              從上面示例程序的運行結(jié)果來看,它是和“不管在何種情況下,在離開當前的作用域時,finally塊區(qū)域內(nèi)的代碼都將會被執(zhí)行到”這條規(guī)則相一致的。

            __leave關(guān)鍵字的作用

              其實,總結(jié)上面的__finally塊被執(zhí)行的流程時,無外乎三種情況。第一種就是順序執(zhí)行到__finally塊區(qū)域內(nèi)的代碼,這種情況很簡單,容易理解;第二種就是goto語句或return語句引發(fā)的程序控制流離開當前__try塊作用域時,系統(tǒng)自動完成對__finally塊代碼的調(diào)用;第三種就是由于在__try塊中出現(xiàn)異常時,導致程序控制流離開當前__try塊作用域,這種情況下也是由系統(tǒng)自動完成對__finally塊的調(diào)用。無論是第 2種,還是第3種情況,毫無疑問,它們都會引起很大的系統(tǒng)開銷,編譯器在編譯此類程序代碼時,它會為這兩種情況準備很多的額外代碼。一般第2種情況,被稱為“局部展開(LocalUnwinding)”;第3種情況,被稱為“全局展開(GlobalUnwinding)”。在后面闡述SEH實現(xiàn)的時候會詳細分析到這一點。
            第3種情況,也即由于出現(xiàn)異常而導致的“全局展開”,對于程序員而言,這也許是無法避免的,因為你在利用異常處理機制提高程序可靠健壯性的同時,不可避免的會引起性能上其它的一些開銷。呵呵!這世界其實也算瞞公平的,有得必有失。

              但是,對于第2種情況,程序員完全可以有效地避免它,避免“局部展開”引起的不必要的額外開銷。實際這也是與結(jié)構(gòu)化程序設計思想相一致的,也即一個程序模塊應該只有一個入口和一個出口,程序模塊內(nèi)盡量避免使用goto語句等。但是,話雖如此,有時為了提高程序的可讀性,程序員在編寫代碼時,有時可能不得不采用一些與結(jié)構(gòu)化程序設計思想相悖的做法,例如,在一個函數(shù)中,可能有多處的return語句。針對這種情況,SEH提供了一種非常有效的折衷方案,那就是__leave關(guān)鍵字所起的作用,它既具有像goto語句和return語句那樣類似的作用(由于檢測到某個程序運行中的錯誤,需要馬上離開當前的 __try塊作用域),但是又避免了“局部展開” 的額外開銷。還是看個例子吧!代碼如下:

            #include <stdio.h>

            void test()
            {
            puts("hello");
            __try
            {
            int* p;
            puts("__try塊中");

            // 直接跳出當前的__try作用域
            __leave;
            p = 0;
            *p = 25;
            }
            __finally
            {
            // 這里會被執(zhí)行嗎?當然
            puts("__finally塊中");
            }

            puts("world");
            }

            void main()
            {
            __try
            {
            test();
            }
            __except(1)
            {
            puts("__except塊中");
            }
            }

            上面的程序運行結(jié)果如下:
            hello
            __try塊中
            __finally塊中
            world
            Press any key to continue

              這就是__leave關(guān)鍵字的作用,也許大家在編程時很少使用它。但是請注意,如果你的程序中,尤其在那些業(yè)務特別復雜的函數(shù)模塊中,既采用了SEH機制來保證程序的可靠性,同時代碼中又擁有大量的goto語句和return語句的話,那么你的源代碼編譯出來的二進制程序?qū)⑹鞘衷愀獾模粌H十分龐大,而且效率也受很大影響。此時,建議不妨多用__leave關(guān)鍵字來提高程序的性能。

            try-finally深入


              現(xiàn)在,相信我們已經(jīng)對try-finally機制有了非常全面的了解,為了更進一步認識try-finally機制的好處(當然,主人公阿愚認為,那些寫過Windows平臺下設備驅(qū)動程序的朋友一定深刻認識到try-finally機制的重要性),這里給出一個具體的例子。還記得,在《第21集 Windows系列操作系統(tǒng)平臺中所提供的異常處理機制》中,所講述到的采用setjmp和longjmp異常處理機制實現(xiàn)的那個簡單例程嗎?現(xiàn)在如果有了try-finally機制,將能夠很容易地來避免內(nèi)存資源的泄漏,而且還極大地提高了程序模塊的可讀性,減少程序員由于不小心造成的程序bug等隱患。采用SEH重新實現(xiàn)的代碼如下:

            #include <stdio.h>
            #include <stdlib.h>

            void test1()
            {
            char* p1, *p2, *p3, *p4;

            __try
            {
            p1 = malloc(10);
            p2 = malloc(10);
            p3 = malloc(10);
            p4 = malloc(10);

            // do other job
            // 期間可能拋出異常
            }
            __finally
            {
            // 這里保證所有資源被及時釋放
            if(p1) free(p1);
            if(p2) free(p2);
            if(p3) free(p3);
            if(p4) free(p4);
            }
            }

            void test()
            {
            char* p;

            __try
            {
            p = malloc(10);

            // do other job
            // 期間可能拋出異常

            test1();

            // do other job
            }
            __finally
            {
            // 這里保證資源被釋放
            if(p) free(p);
            }
            }

            void main( void )
            {
            __try
            {
            char* p;

            __try
            {
            p = malloc(10);

            // do other job

            // 期間可能拋出異常
            test();

            // do other job
            }
            __finally
            {
            // 這里保證資源被釋放
            if(p) free(p);
            }
            }
            __except(1)
            {
            printf("捕獲到一個異常\n");
            }
            }

              呵呵!上面的代碼與采用setjmp和longjmp機制實現(xiàn)的代碼相比,是不是更簡潔,更美觀。這就是try-finally語句的貢獻所在。

            總結(jié)

               (1) “不管在何種情況下,在離開當前的作用域時,finally塊區(qū)域內(nèi)的代碼都將會被執(zhí)行到”,這是核心法則。

               (2) try-finally語句的作用相當于面向?qū)ο笾械奈鰳?gòu)函數(shù)。

               (3) goto語句和return語句,在其它少數(shù)情況下,break語句以及continue語句等,它們都可能會導致程序的控制流非正常順序地離開 __try作用域,此時會發(fā)生SEH的“局部展開”。記住,“局部展開”會帶來較大的開銷,因此,程序員應該盡可能采用__leave關(guān)鍵字來減少一些不必要的額外開銷。

              通過這幾篇文章中對SEH異常處理機制的深入闡述,相信大家已經(jīng)能夠非常熟悉使用SEH來進行編程了。下一篇文章把try-except和try-finally機制結(jié)合起來,進行一個全面而綜合的評述,繼續(xù)吧!

            posted on 2008-01-25 19:29 大龍 閱讀(517) 評論(0)  編輯 收藏 引用

            久久国产精品久久精品国产| 久久综合亚洲色一区二区三区| 欧洲性大片xxxxx久久久| 99久久精品国产麻豆| 久久丝袜精品中文字幕| 少妇无套内谢久久久久| 2021国产精品午夜久久| 久久久久久久久久久久中文字幕 | 日韩精品久久无码中文字幕| 久久精品亚洲一区二区三区浴池| 丰满少妇人妻久久久久久| 国产综合成人久久大片91| 亚洲精品国产第一综合99久久| 无码精品久久久久久人妻中字| 国产高清美女一级a毛片久久w| 午夜精品久久久久| 久久亚洲精品视频| 亚洲va久久久噜噜噜久久男同| 久久久黄片| 亚洲а∨天堂久久精品9966| 亚洲国产精品无码久久SM| 久久伊人中文无码| 国产精品久久久久久久午夜片| 亚洲愉拍99热成人精品热久久| 久久久久九九精品影院| 久久er国产精品免费观看2| 久久这里有精品| 久久高潮一级毛片免费| 久久精品国产精品青草app| 蜜臀av性久久久久蜜臀aⅴ | 人人狠狠综合久久88成人| 思思久久99热免费精品6| 久久精品无码一区二区三区| 九九久久自然熟的香蕉图片| 99久久精品免费看国产一区二区三区| 久久久久国产精品三级网| 久久99精品久久久久久噜噜| 亚洲午夜精品久久久久久人妖| 国内精品久久久久久99蜜桃| 久久精品亚洲日本波多野结衣| 亚洲成色WWW久久网站|