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

            Prayer

            在一般中尋求卓越
            posts - 1256, comments - 190, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            玩轉setjmp與longjmp

            Posted on 2009-05-19 11:30 Prayer 閱讀(301) 評論(0)  編輯 收藏 引用 所屬分類: C/C++ 、LINUX/UNIX/AIX
            不要忘記,前面我們得出過結論,C語言中提供的這種異常處理機制,與C++中的異常處理模型很相似。例如,可以定義出類似的try block(受到監控的代碼);catch block(異常錯誤的處理模塊);以及可以隨時拋出的異常(throw語句)。所以說,我們可以通過一種非常有技巧的封裝,來達到對setjmp和longjmp的使用方法(或者說語法規則),基本與C++中的語法一致。很有誘惑吧!

            首先展示阿愚封裝的在C語言環境中異常處理框架

              1、首先是接口的頭文件,主要采用“宏”技術!代碼如下:

            /*************************************************
            * author: 王勝祥 *
            * email: <mantx@21cn.com> *
            * date: 2005-03-07 *
            * version: *
            * filename: ceh.h *
            *************************************************/


            /********************************************************************

            This file is part of CEH(Exception Handling in C Language).

            CEH is free software; you can redistribute it and/or modify
            it under the terms of the GNU General Public License as published by
            the Free Software Foundation; either version 2 of the License, or
            (at your option) any later version.

            CEH is distributed in the hope that it will be useful,
            but WITHOUT ANY WARRANTY; without even the implied warranty of
            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
            GNU General Public License for more details.

              注意:這個異常處理框架不支持線程安全,不能在多線程的程序環境下使用。
            如果您想在多線程的程序中使用它,您可以自己試著來繼續完善這個
            框架模型。
            *********************************************************************/

            #include <stdio.h>
            #include <signal.h>
            #include <setjmp.h>
            #include <stdlib.h>
            #include <float.h>
            #include <math.h>
            #include <string.h>


            ////////////////////////////////////////////////////
            /* 與異常有關的結構體定義 */
            typedef struct _CEH_EXCEPTION {
            int err_type; /* 異常類型 */
            int err_code; /* 錯誤代碼 */
            char err_msg[80]; /* 錯誤信息 */
            }CEH_EXCEPTION; /* 異常對象 */

            typedef struct _CEH_ELEMENT {
            jmp_buf exec_status;
            CEH_EXCEPTION ex_info;

            struct _CEH_ELEMENT* next;
            } CEH_ELEMENT; /* 存儲異常對象的鏈表元素 */
            ////////////////////////////////////////////////////


            ////////////////////////////////////////////////////
            /* 內部接口定義,操縱維護鏈表數據結構 */
            extern void CEH_push(CEH_ELEMENT* ceh_element);
            extern CEH_ELEMENT* CEH_pop();
            extern CEH_ELEMENT* CEH_top();
            extern int CEH_isEmpty();
            ////////////////////////////////////////////////////


            /* 以下是外部接口的定義 */
            ////////////////////////////////////////////////////
            /* 拋出異常 */
            extern void thrower(CEH_EXCEPTION* e);

            /* 拋出異常 (throw)
            a表示err_type
            b表示err_code
            c表示err_msg
            */
            #define throw(a, b, c)
            {
            CEH_EXCEPTION ex;
            memset(&ex, 0, sizeof(ex));
            ex.err_type = a;
            ex.err_code = b;
            strncpy(ex.err_msg, c, sizeof(c));
            thrower(&ex);
            }

            /* 重新拋出原來的異常 (rethrow)*/
            #define rethrow thrower(ceh_ex_info)
            ////////////////////////////////////////////////////


            ////////////////////////////////////////////////////
            /* 定義try block(受到監控的代碼)*/
            #define try
            {
            int ___ceh_b_catch_found, ___ceh_b_occur_exception;
            CEH_ELEMENT ___ceh_element;
            CEH_EXCEPTION* ceh_ex_info;
            memset(&___ceh_element, 0, sizeof(___ceh_element));
            CEH_push(&___ceh_element);
            ceh_ex_info = &___ceh_element.ex_info;
            ___ceh_b_catch_found = 0;
            if (!(___ceh_b_occur_exception=setjmp(___ceh_element.exec_status)))
            {


            /* 定義catch block(異常錯誤的處理模塊)
            catch表示捕獲所有類型的異常
            */
            #define catch
            }
            else
            {
            CEH_pop();
            ___ceh_b_catch_found = 1;


            /* end_try表示前面定義的try block和catch block結束 */
            #define end_try
            }
            {
            /* 沒有執行到任何的catch塊中 */
            if(!___ceh_b_catch_found)
            {
            CEH_pop();
            /* 出現了異常,但沒有捕獲到任何異常 */
            if(___ceh_b_occur_exception) thrower(ceh_ex_info);
            }
            }
            }


            /* 定義catch block(異常錯誤的處理模塊)
            catch_part表示捕獲一定范圍內的異常
            */
            #define catch_part(i, j)
            }
            else if(ceh_ex_info->err_type>=i && ceh_ex_info->err_type<=j)
            {
            CEH_pop();
            ___ceh_b_catch_found = 1;


            /* 定義catch block(異常錯誤的處理模塊)
            catch_one表示只捕獲一種類型的異常
            */
            #define catch_one(i)
            }
            else if(ceh_ex_info->err_type==i)
            {
            CEH_pop();
            ___ceh_b_catch_found = 1;
            ////////////////////////////////////////////////////


            ////////////////////////////////////////////////////
            /* 其它可選的接口定義 */
            extern void CEH_init();
            ////////////////////////////////////////////////////


            2、另外還有一個簡單的實現文件,主要實現功能封裝。代碼如下:

            /*************************************************
            * author: 王勝祥 *
            * email: <mantx@21cn.com> *
            * date: 2005-03-07 *
            * version: *
            * filename: ceh.c *
            *************************************************/


            /********************************************************************

            This file is part of CEH(Exception Handling in C Language).

            CEH is free software; you can redistribute it and/or modify
            it under the terms of the GNU General Public License as published by
            the Free Software Foundation; either version 2 of the License, or
            (at your option) any later version.

            CEH is distributed in the hope that it will be useful,
            but WITHOUT ANY WARRANTY; without even the implied warranty of
            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
            GNU General Public License for more details.

            注意:這個異常處理框架不支持線程安全,不能在多線程的程序環境下使用。
            如果您想在多線程的程序中使用它,您可以自己試著來繼續完善這個
            框架模型。
            *********************************************************************/

            #include "ceh.h"

            ////////////////////////////////////////////////////
            static CEH_ELEMENT* head = 0;

            /* 把一個異常插入到鏈表頭中 */
            void CEH_push(CEH_ELEMENT* ceh_element)
            {
            if(head) ceh_element->next = head;
            head = ceh_element;
            }


            /* 從鏈表頭中,刪除并返回一個異常 */
            CEH_ELEMENT* CEH_pop()
            {
            CEH_ELEMENT* ret = 0;

            ret = head;
            head = head->next;

            return ret;
            }


            /* 從鏈表頭中,返回一個異常 */
            CEH_ELEMENT* CEH_top()
            {
            return head;
            }


            /* 鏈表中是否有任何異常 */
            int CEH_isEmpty()
            {
            return head==0;
            }
            ////////////////////////////////////////////////////


            ////////////////////////////////////////////////////
            /* 缺省的異常處理模塊 */
            static void CEH_uncaught_exception_handler(CEH_EXCEPTION *ceh_ex_info)
            {
            printf("捕獲到一個未處理的異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            fprintf(stderr, "程序終止! ");
            fflush(stderr);
            exit(EXIT_FAILURE);
            }
            ////////////////////////////////////////////////////


            ////////////////////////////////////////////////////
            /* 拋出異常 */
            void thrower(CEH_EXCEPTION* e)
            {
            CEH_ELEMENT *se;

            if (CEH_isEmpty()) CEH_uncaught_exception_handler(e);

            se = CEH_top();
            se->ex_info.err_type = e->err_type;
            se->ex_info.err_code = e->err_code;
            strncpy(se->ex_info.err_msg, e->err_msg, sizeof(se->ex_info.err_msg));

            longjmp(se->exec_status, 1);
            }
            ////////////////////////////////////////////////////


            ////////////////////////////////////////////////////
            static void fphandler( int sig, int num )
            {
            _fpreset();

            switch( num )
            {
            case _FPE_INVALID:
            throw(-1, num, "Invalid number" );
            case _FPE_OVERFLOW:
            throw(-1, num, "Overflow" );
            case _FPE_UNDERFLOW:
            throw(-1, num, "Underflow" );
            case _FPE_ZERODIVIDE:
            throw(-1, num, "Divide by zero" );
            default:
            throw(-1, num, "Other floating point error" );
            }
            }

            void CEH_init()
            {
            _control87( 0, _MCW_EM );

            if( signal( SIGFPE, fphandler ) == SIG_ERR )
            {
            fprintf( stderr, "Couldn't set SIGFPE " );
            abort();
            }
            }
            ////////////////////////////////////////////////////
              體驗上面設計出的異常處理框架
            請花點時間仔細揣摩一下上面設計出的異常處理框架。呵呵!程序員朋友們,大家是不是發現它與C++提供的異常處理模型非常相似。例如,它提供的基本接口有 try、catch、以及throw等三條語句。還是先看個具體例子吧!以便驗證一下這個C語言環境中異常處理框架是否真的比較好用。代碼如下:

            #include "ceh.h"

            int main(void)
            {
            //定義try block塊
            try
            {
            int i,j;
            printf("異常出現前 ");

            // 拋出一個異常
            // 其中第一個參數,表示異常類型;第二個參數表示錯誤代碼
            // 第三個參數表示錯誤信息
            throw(9, 15, "出現某某異常");

            printf("異常出現后 ");
            }
            //定義catch block塊
            catch
            {
            printf("catch塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            // 這里稍有不同,需要定義一個表示當前的try block結束語句
            // 它主要是清除相應的資源
            end_try
            }

              注意,上面的測試程序可是C語言環境下的程序(文件的擴展名請使用.c結尾),雖然它看上去很像C++程序。請編譯運行一下,發現它是不是運行結果如下:
            異常出現前

            catch塊,被執行到

              捕獲到一個異常,錯誤原因是:出現某某異常! err_type:9 err_code:15

              呵呵!程序的確是在按照我們預想的流程在執行。再次提醒,這可是C程序,但是它的異常處理卻非常類似于C++中的風格,要知道,做到這一點其實非常地不容易。當然,上面異常對象的傳遞只是在一個函數的內部,同樣,它也適用于多個嵌套函數間的異常傳遞,還是用代碼驗證一下吧!在上面的代碼基礎下,小小修改一點,代碼如下:

            #include "ceh.h"

            void test1()
            {
            throw(0, 20, "hahaha");
            }

            void test()
            {
            test1();
            }

            int main(void)
            {
            try
            {
            int i,j;
            printf("異常出現前 ");

            // 注意,這個函數的內部會拋出一個異常。
            test();

            throw(9, 15, "出現某某異常");

            printf("異常出現后 ");
            }
            catch
            {
            printf("catch塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try
            }

              同樣,在上面程序中,test1()函數內拋出的異常,可以被上層main()函數中的catch block中捕獲到。運行結果就不再給出了,大家可以自己編譯運行一把,看看運行結果。
            另外這個異常處理框架,與C++中的異常處理模型類似,它也支持try catch塊的多層嵌套。很厲害吧!還是看演示代碼吧!,如下:

            #include "ceh.h"

            int main(void)
            {
            // 外層的try catch塊
            try
            {
            // 內層的try catch塊
            try
            {
            throw(1, 15, "嵌套在try塊中");
            }
            catch
            {
            printf("內層的catch塊被執行 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);

            printf("外層的catch塊被執行 ");
            }
            end_try

            throw(2, 30, "再拋一個異常");
            }
            catch
            {
            printf("外層的catch塊被執行 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try
            }

              請編譯運行一下,程序的運行結果如下:
              內層的catch塊被執行
              捕獲到一個異常,錯誤原因是:嵌套在try塊中! err_type:1 err_code:15
              外層的catch塊被執行
              捕獲到一個異常,錯誤原因是:再拋一個異常! err_type:2 err_code:30

              還有,這個異常處理框架也支持對異常的分類處理。這一點,也完全是模仿C++中的異常處理模型。不過,由于C語言中,不支持函數名重載,所以語法上略有不同,還是看演示代碼吧!,如下:

            #include "ceh.h"

            int main(void)
            {
            try
            {
            int i,j;
            printf("異常出現前 ");

            throw(9, 15, "出現某某異常");

            printf("異常出現后 ");
            }
            // 這里表示捕獲異常類型從4到6的異常
            catch_part(4, 6)
            {
            printf("catch_part(4, 6)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            // 這里表示捕獲異常類型從9到10的異常
            catch_part(9, 10)
            {
            printf("catch_part(9, 10)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            // 這里表示只捕獲異常類型為1的異常
            catch_one(1)
            {
            printf("catch_one(1)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            // 這里表示捕獲所有類型的異常
            catch
            {
            printf("catch塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try
            }

              請編譯運行一下,程序的運行結果如下:
              異常出現前

            catch_part(9, 10)塊,被執行到
              捕獲到一個異常,錯誤原因是:出現某某異常! err_type:9 err_code:15

              與C++中的異常處理模型相似,它這里的對異常的分類處理不僅支持一維線性的;同樣,它也支持分層的,也即在當前的try catch塊中找不到相應的catch block,那么它將會到上一層的try catch塊中繼續尋找。演示代碼如下:

            #include "ceh.h"

            int main(void)
            {
            try
            {
            try
            {
            throw(1, 15, "嵌套在try塊中");
            }
            catch_part(4, 6)
            {
            printf("catch_part(4, 6)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try

            printf("這里將不會被執行到 ");
            }
            catch_part(2, 3)
            {
            printf("catch_part(2, 3)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            // 找到了對應的catch block
            catch_one(1)
            {
            printf("catch_one(1)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            catch
            {
            printf("catch塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try

            }

              到目前為止,大家是不是已經覺得,這個主人公阿愚封裝的在C語言環境中異常處理框架,已經與C++中的異常處理模型95%相似。無論是它的語法結構;還是所完成的功能;以及它使用上的靈活性等。下面我們來看一個各種情況綜合的例子吧!代碼如下:

            #include "ceh.h"

            void test1()
            {
            throw(0, 20, "hahaha");
            }

            void test()
            {
            test1();
            }

            int main(void)
            {
            try
            {
            test();
            }
            catch
            {
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try

            try
            {
            try
            {
            throw(1, 15, "嵌套在try塊中");
            }
            catch
            {
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try

            throw(2, 30, "再拋一個異常");
            }
            catch
            {
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);

            try
            {
            throw(0, 20, "嵌套在catch塊中");
            }
            catch
            {
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            end_try
            }
            end_try
            }

              請編譯運行一下,程序的運行結果如下:
              捕獲到一個異常,錯誤原因是:hahaha! err_type:0 err_code:20
              捕獲到一個異常,錯誤原因是:嵌套在try塊中! err_type:1 err_code:15
              捕獲到一個異常,錯誤原因是:再拋一個異常! err_type:2 err_code:30
              捕獲到一個異常,錯誤原因是:嵌套在catch塊中! err_type:0 err_code:20

              最后,為了體會到這個異常處理框架,更進一步與C++中的異常處理模型相似。那就是它還支持異常的重新拋出,以及系統中能捕獲并處理程序中沒有catch到的異常。看代碼吧!如下:

            #include "ceh.h"

            void test1()
            {
            throw(0, 20, "hahaha");
            }

            void test()
            {
            test1();
            }

            int main(void)
            {
            // 這里表示程序中將捕獲浮點數計算異常
            CEH_init();

            try
            {
            try
            {
            try
            {
            double i,j;
            j = 0;
            // 這里出現浮點數計算異常
            i = 1/j ;

            test();

            throw(9, 15, "出現某某異常");
            }
            end_try
            }
            catch_part(4, 6)
            {
            printf("catch_part(4, 6)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            catch_part(2, 3)
            {
            printf("catch_part(2, 3)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
            }
            // 捕獲到上面的異常
            catch
            {
            printf("內層的catch塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);

            // 這里再次把上面的異常重新拋出
            rethrow;

            printf("這里將不會被執行到 ");
            }
            end_try
            }
            catch_part(7, 9)
            {
            printf("catch_part(7, 9)塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);

            throw(2, 15, "出現某某異常");
            }
            // 再次捕獲到上面的異常
            catch
            {
            printf("外層的catch塊,被執行到 ");
            printf("捕獲到一個異常,錯誤原因是:%s! err_type:%d err_code:%d ",
            ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);

            // 最后又拋出了一個異常,
            // 但是這個異常沒有對應的catch block處理,所以系統中處理了
            throw(2, 15, "出現某某異常");
            }
            end_try
            }

              請編譯運行一下,程序的運行結果如下:
              內層的catch塊,被執行到
              捕獲到一個異常,錯誤原因是:Divide by zero! err_type:-1 err_code:131
              外層的catch塊,被執行到
              捕獲到一個異常,錯誤原因是:Divide by zero! err_type:-1 err_code:131
              捕獲到一個未處理的異常,錯誤原因是:出現某某異常! err_type:2 err_code:15
              程序終止!
            久久综合久久综合亚洲| 精品综合久久久久久98| 伊人久久大香线蕉av一区| 久久人妻AV中文字幕| 久久亚洲精精品中文字幕| 亚洲成色WWW久久网站| 色综合久久88色综合天天| 久久伊人精品青青草原日本| 久久久久综合中文字幕| 伊人精品久久久久7777| 久久精品国产久精国产思思| 久久狠狠一本精品综合网| 亚洲伊人久久大香线蕉综合图片| 日产精品久久久一区二区| 女同久久| 亚洲а∨天堂久久精品| 欧美激情精品久久久久| 亚洲AV无码久久精品色欲| 精品国产一区二区三区久久| 久久中文字幕视频、最近更新| 亚洲人成电影网站久久| 欧美久久一区二区三区| 久久精品国产WWW456C0M| 99久久人妻无码精品系列蜜桃 | 无码人妻久久一区二区三区免费| 女人香蕉久久**毛片精品| 久久久久久久综合日本亚洲 | 久久久久久久亚洲精品| 国产精品久久精品| 亚洲综合婷婷久久| 久久香综合精品久久伊人| 成人午夜精品无码区久久| 久久久久无码精品国产不卡| 99久久超碰中文字幕伊人| 久久精品国产亚洲麻豆| 国产日韩久久免费影院| 婷婷国产天堂久久综合五月| 久久精品国产亚洲av麻豆小说| 国产午夜免费高清久久影院| 欧美性大战久久久久久| 国产精品久久久久久吹潮|