快捷搜索:   服务器  安全  linux 安全  MYSQL  dedecms

玩转setjmp与longjmp

    不要忘记,前面我们得出过结论,C语言中提供的这种异常处理机制,与C++中的异常处理模型很相似。例如,可以定义出类似的try block(受到监控的代码);catch block(异常错误的处理模块);以及可以随时抛出的异常(throw语句)。所以说,我们可以通过一种非常有技巧的封装,来达到对setjmp和longjmp的使用方法(或者说语法规则),基本与C++中的语法一致。很有诱惑吧!
    首先展示阿愚封装的在C语言环境中异常处理框架

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

    /*************************************************
    * author: 王胜祥 *
    * email: <[email protected]> *
    * 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: <[email protected]> *
    * 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\n",
    ceh_ex_info->err_msg, ceh_ex_info->err_type, ceh_ex_info->err_code);
    fprintf(stderr, "程序终止!\n");
    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\n" );
    abort();
    }
    }
    ////////////////////////////////////////////////////
      体验上面设计出的异常处理框架
    请花点时间仔细揣摩一下上面设计出的异常处理框架。呵呵!程序员朋友们,大家是不是发现它与C++提供的异常处理模型非常相似。例如,它提供的基本接口有 try、catch、以及throw等三条语句。还是先看个具体例子吧!以便验证一下这个C语言环境中异常处理框架是否真的比较好用。代码如下:

    #include "ceh.h"

    int main(void)
    {
    //定义try block块
    try
    {
    int i,j;
    printf("异常出现前\n\n");

    // 抛出一个异常
    // 其中第一个参数,表示异常类型;第二个参数表示错误代码
    // 第三个参数表示错误信息
    throw(9, 15, "出现某某异常");

    printf("异常出现后\n\n");
    }
    //定义catch block块
    catch
    {
    printf("catch块,被执行到\n");
    printf("捕获到一个异常,错误原因是:%s! err_type:%d err_code:%d\n",
    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;

顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论