• <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>
            posts - 311, comments - 0, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            一、   綜述

            SEH--Structured Exception Handling,是Windows操作系統(tǒng)使用的異常處理方式。

            對于SEH,有點需要說明的是,SEH是屬于操作系統(tǒng)的特性,不為特定語言設計,但是實際上,作為操作系統(tǒng)的特性,幾乎就等同與面向C語言設計,這點很好理解,就像Win32 API,Linux下的系統(tǒng)調用,都是操作系統(tǒng)的特性吧,實際還是為C做的。但是,作為為C語言設計的東西,實際上可調用的方式又多了,匯編,C++對于調用C語言的接口都是比較方便的。

             

            二、   基礎篇

            還是簡單介紹一下SEH的使用,但是不準備太詳細的介紹了,具體的詳細介紹見參考中提及的書目。關于SEH的基本應用,Windows核心編程》絕對是最佳讀物(其實個人一直認為《Windows核心編程》是Windows編程領域必看的第二本書,第一本是《Programming Windows》。關于SEH更深入的一點的知識可能就要參考一些能用匯編講解的書籍了,《Windows用戶態(tài)程序高效排錯》算是其中講的不錯的一本。

            首先,SEH也有像C++異常一樣的語法,及類try-catch語法,在SEH中為__try-except語法,拋出異常從throw改為RaiseException,MSDN中的語法描述為:

            __try 

            {

               // guarded code

            }

            __except ( expression )

            {

               // exception handler code

            }

             

            見一個實際使用的例子:

            1

            #include <iostream>

            #include <windows.h>

            using namespace std;

             

            int main()

            {

                __try

                {

                   RaiseException(0, 0, 0, NULL);

                }

                __except(EXCEPTION_EXECUTE_HANDLER)

                {

                   cout <<"Exception Raised." <<endl;

             

                }

             

                cout <<"Continue running" <<endl;

            }

             

            這可能是最簡單的SEH的例子了,輸出如下:

            Exception Raised.

            Continue running

             

            這個例子和普通C++異常的try-catch類似,也很好理解。只不過catch換成了except。

            因為C語言沒有智能指針,那么就不能缺少finally的異常語法,與JAVA,Python等語言中的也類似,(這是C++中沒有的)finally語法的含義就是無論如何(不管是正常還是異常),此句總是會執(zhí)行,常用于資源釋放。

             

            2

             

            #include <iostream>

            #include <windows.h>

            using namespace std;

             

            int main()

            {

                __try

                {

             

                   __try

                   {

                       RaiseException(0, 0, 0, NULL);

                   }

                   __finally

                   {

                       cout <<"finally here." <<endl;

             

                   }

                }

                __except(1)

                {

             

                }

             

                __try

                {

             

                   __try

                   {

                       int i;

                   }

                   __finally

                   {

                       cout <<"finally here." <<endl;

             

                   }

                }

                __except(1)

                {

             

                }

                cout <<"Continue running" <<endl;

                getchar();

            }

             

            這個實例看起來過于奇怪,因為沒有將各個try-finally放入獨立的模塊之中,但是說明了問題:

            1.     finally的語句總是會執(zhí)行,無論是否異常finally here總是會輸出。

            2.     finally僅僅是一條保證finally語句執(zhí)行的塊,并不是異常處理的handle語句(與except不同),所以,假如光是有finally語句塊的話,實際效果就是異常會繼續(xù)向上拋出。(異常處理過程也還是繼續(xù))

            3.     finally執(zhí)行后還可以用except繼續(xù)處理異常,但是SEH奇怪的語法在于finallyexcept無法同時使用,不然會報編譯錯誤。

            如下例:

                __try

                {

                   RaiseException(0, 0, 0, NULL);

                }

                __except(1)

                {

             

                }

                __finally

                {

                   cout <<"finally here." <<endl;

             

                }

             

            VS2005會報告

            error C3274: __finally 沒有匹配的try

            這點其實很奇怪,難道因為SEH設計過于老了?-_-!因為在現(xiàn)在的語言中finally都是允許與except(或類似的塊,比如catch)同時使用的。C#,JAVA,Python都是如此,甚至在MSC++做的托管擴展中都是允許的。如下例:(來自MSDN中對finally keyword [C++]的描述)

            using namespace System;

             

            ref class MyExceptionpublic System::Exception{};

             

            void ThrowMyException() {

                throw gcnew MyException;

            }

             

            int main() {

                try {

                   ThrowMyException();

                }

                catch ( MyExceptione ) {

                   Console::WriteLine(  "in catch" );

                   Console::WriteLinee->GetType() );

                }

                finally {

                   Console::WriteLine(  "in finally" );

                }

            }

             

            當你不習慣使用智能指針的時候常常會覺得這樣會很好用。關于finally異常語法和智能指針的使用可以說是各有長短,這里提供劉未鵬的一種解釋,(見參考5RAII部分,文中比較的雖然是JAVAC#,但是實際SEH也是類似JAVA的)大家參考參考。

             

            SEH中還提供了一個比較特別的關鍵字,__leave,MSDN中解釋如下

            Allows for immediate termination of the __try block without causing abnormal termination and its performance penalty.

            簡而言之就是類似goto語句的拋出異常方式,所謂的沒有性能損失是什么意思呢?看看下面的例子:

            #include <iostream>

            #include <windows.h>

            using namespace std;

             

            int main()

            {

                int i = 0;

                __try

                {

                   __leave;

                   i = 1;

                }

                __finally

                {

                   cout <<"i: " <<i <<" finally here." <<endl;

                }

             

             

                cout <<"Continue running" <<endl;

                getchar();

            }

             

             

            輸出:

            i: 0 finally here.

            Continue running

            實際就是類似Goto語句,沒有性能損失指什么?一般的異常拋出也是沒有性能損失的。

            MSDN解釋如下:

            The __leave keyword

            The __leave keyword is valid within a try-finally statement block. The effect of __leave is to jump to the end of the try-finally block. The termination handler is immediately executed. Although a goto statement can be used to accomplish the same result, a goto statement causes stack unwinding. The __leave statement is more efficient because it does not involve stack unwinding.

             

            意思就是沒有stack unwinding,問題是。。。。。。如下例,實際會導致編譯錯誤,所以實在不清楚到__leave到底干啥的,我實際中也從來沒有用過此關鍵字。

             

            #include <iostream>

            #include <windows.h>

            using namespace std;

             

             

            void fun()

            {

                __leave;

            }

             

            int main()

            {

                __try

                {

                   fun();

                }

                __finally

                {

                   cout <<" finally here." <<endl;

                }

             

             

                cout <<"Continue running" <<endl;

                getchar();

            }

             

            三、   提高篇

            1.      SEH的優(yōu)點

            1)    一個很大的優(yōu)點就是其對異常進程的完全控制,這一點是C++異常所沒有的,因為其遵循的是所謂的終止設定。

            這一點是通過except中的表達式來控制的(在前面的例子中我都是用1表示,實際也就是使用了EXCEPTION_EXECUTE_HANDLER方式。

            EXCEPTION_CONTINUE_EXECUTION (–1)   表示在異常發(fā)生的地方繼續(xù)執(zhí)行,表示處理過后,程序可以繼續(xù)執(zhí)行下去。 C++中沒有此語義。

            EXCEPTION_CONTINUE_SEARCH (0)   異常沒有處理,繼續(xù)向上拋出。類似C++throw;

            EXCEPTION_EXECUTE_HANDLER (1)  異常被處理,從異常處理這一層開始繼續(xù)執(zhí)行。 類似C++處理異常后不再拋出。

             

             

            2)    操作系統(tǒng)特性,不僅僅意味著你可以在更多場合使用SEH(甚至在匯編語言中使用),實際對異常處理的功能也更加強大,甚至是程序的嚴重錯誤也能恢復(不僅僅是一般的異常),比如,除0錯誤,訪問非法地址(包括空指針的使用)等。這里可以用一個例子來說明:

            #include <iostream>

            #include <windows.h>

            using namespace std;

             

             

             

            int main()

            {

                __try

                {

                   int *p = NULL;

                   *p = 0;

                }

                __except(1)

                {

                   cout <<"catch that" <<endl;

                }

             

             

                cout <<"Continue running" <<endl;

                getchar();

            }

             

            輸出:

            catch that

            Continue running

            C++中這樣的情況會導致程序直接崩潰的,這一點好好利用,可以使得你的程序穩(wěn)定性大增,以彌補C++中很多的不足。但是,問題又來了,假如異常都被這樣處理了,甚至沒有聲息,非常不符合發(fā)生錯誤時死的壯烈的錯誤處理原則。。。。。。。很可能導致程序一堆錯誤,你甚至不知道為什么,這樣不利于發(fā)現(xiàn)錯誤。

            但是,SEHMS提供的另外的特性MiniDump可以完美的配合在一起,使得錯誤得到控制,但是錯誤情況也能捕獲到,稍微的緩解了這種難處(其實也說不上完美解決)。

            這一點需要使用者自己權衡,看看到底開發(fā)進入了哪個階段,哪個更加重要,假如是服務器程序,那么在正式跑著的時候,每崩潰一次就是實際的損失。。。所以在后期可以考慮用這種方式。

            關于這方面的信息,在下一次在詳細講解。

             

            2.      SEH的缺點

            其實還是有的,因為是為操作系統(tǒng)設計的,實際類似為C設計,那么,根本就不知道C++中類/對象的概念,所以,實際上不能識別并且正確的與C++/對象共存,這一點使用C++的需要特別注意,比如下例的程序根本不能通過編譯。

            例一:

            int main()

            {

                CMyClass o;

                __try

                {

                }

                __except(1)

                {

                   cout <<"catch that" <<endl;

                }

             

             

                cout <<"Continue running" <<endl;

                getchar();

            }

             

            例二:

             

            int main()

            {

                __try

                {

                   CMyClass o;

                }

                __except(1)

                {

                   cout <<"catch that" <<endl;

                }

             

             

                cout <<"Continue running" <<endl;

                getchar();

            }

             

             

            錯誤信息都為:

            warning C4509: 使用了非標準擴展:“main”使用SEH,并且“o”有析構函數(shù)

            error C2712: 無法在要求對象展開的函數(shù)中使用__try

            這點比較遺憾,但是我們還是有折衷的辦法的,那就是利用函數(shù)的特性,這樣可以避開SEH的不足。

            比如,希望使用類的使用可以這樣:

            這個類利用了上節(jié)的CResourceObserver類,

            class CMyClass : public CResourceObserver<CMyClass>

            {

             

            };

             

            void fun()

            {

                CMyClass o;

            }

             

             

            #include <iostream>

            #include <windows.h>

            using namespace std;

             

             

            int main()

            {

                __try

                {

                   fun();

                }

                __except(1)

                {

                   cout <<"catch that" <<endl;

                }

             

             

                cout <<"Continue running" <<endl;

                getchar();

            }

             

             

            輸出:

            class CMyClass Construct.

            class CMyClass Deconstruct.

            Continue running

            可以看到正常的析構,簡而言之就是將實際類/對象的使用全部放進函數(shù)中,利用函數(shù)對對象生命周期的控制,來避開SEH的不足。

             

             

            四、   參考資料

            1.     Windows核心編程(Programming Applications for Microsoft Windows,4版,Jeffrey Richter著,黃隴,李虎譯,機械工業(yè)出版社

            2.     MSDN—Visual Studio 2005 附帶版,Microsoft

            3.     加密與解密,段鋼編著,電子工業(yè)出版社

            4.     Windows用戶態(tài)程序高效排錯,熊力著,電子工業(yè)出版社

            5. 錯誤處理(Error-Handling):為何、何時、如何(rev#2),劉未鵬(pongba)

            99久久久国产精品免费无卡顿| 久久久久久久综合狠狠综合| 性高湖久久久久久久久| 国产成人无码精品久久久性色| 久久天天躁狠狠躁夜夜不卡| 亚洲av伊人久久综合密臀性色| 香蕉久久夜色精品升级完成| 国产精品久久久久jk制服| 一本伊大人香蕉久久网手机| 亚洲欧美另类日本久久国产真实乱对白 | 中文字幕久久久久人妻| 久久久久久人妻无码| 韩国三级中文字幕hd久久精品| 国产偷久久久精品专区| 一本色道久久88精品综合 | 久久久久久久综合狠狠综合| 亚洲香蕉网久久综合影视| 国产一级做a爰片久久毛片| 久久久久久曰本AV免费免费| 激情五月综合综合久久69| 伊人久久大香线蕉综合Av| 久久这里只有精品视频99| 久久91精品国产91久久麻豆| 亚洲AV日韩AV永久无码久久| 久久久久亚洲av毛片大| 久久国产精品-国产精品| 婷婷久久久亚洲欧洲日产国码AV | 久久久久国产成人精品亚洲午夜| 久久久精品国产免大香伊| 久久66热人妻偷产精品9| 精品国产青草久久久久福利| 蜜臀久久99精品久久久久久小说| 色婷婷噜噜久久国产精品12p| 精品无码久久久久久久久久| 人人狠狠综合久久亚洲88| 国产精品美女久久久| 成人综合伊人五月婷久久| 久久午夜无码鲁丝片| 99久久无色码中文字幕| 国产精品99久久精品| 亚洲伊人久久大香线蕉苏妲己|