只要经过 setjmp() 初始化,即可在任何时候调用 longjmp() 转跳到 setjmp() 函数位置,
setjmp() 与 longjmp()
原型:
    void _Cdecl longjmp(jmp_buf jmpb, int retval);
    int _Cdecl setjmp(jmp_buf jmpb);
    在使用 setjmp() 与 longjmp() 之前,需要弄懂一个数据结构 jmp_buf,
    此结构是 setjmp 接口(setjmp.h)的基本数据类型,jmp_buf 结构内容无须深入了解,
    只需要知道,jmp_buf 将记录某一时刻CPU寄存器的值即可,setjmp() 函数可以返回两次,
    第一次使用时作初始化一个 jmp_buf 的量(将当前CPU寄存器的值写入 jmpb 结构内),然后函数返回零;
    第二次是由异常抛出函数 longjmp() 引发,使 setjmp() 函数产生第二次返回,返回值为 retval。
    longjmp() 将 jmpb 内容恢复到寄存器内,执行位置将改变到 setjmp() 处,
    在调用后,longjmp() 后面的代码将毫无意义,并且越过前面所有的函数(将不会再经过 return 逐层返回),
    而是直接跳转到 setjmp() 位置。
    _Cdecl 声明函数的参数使用标准的进栈方式(由右向左)压栈。
异常处理
    goto 语句只可在函数内跳转,setjmp 与 longjmp 函数配合使用,
    可以实现在函数之间跳转(远程跳转),
    所以,C语言使用 setjmp() 及 longjmp() 实现异常处理机制。
    setjmp() 设置跳转位置,longjmp()实现转跳。
    在面向对象语言中由语言内部便提供了异常处理,如C++语言,
    使用 try 块包裹可能产生异常的代码(包括函数调用),
    catch 块用于编写异常处理代码;
    异常由手动的 throw 语句抛出。
    使用 C 简单地模拟 C++ 的异常处理语句是十分容易的,
    此前,值得说明一点的是:jmp_buf 声明的变量多数情况下需要被声明为全局的,
    这是因为 longjmp() 一般不在 try 块内部调用,try 块内一般会调用另外一些函数,
    而 longjmp() 经常在这些函数内抛出。
    jmp_buf Jump_Buffer;
    #define try if(!setjmp(Jump_Buffer))
    #define catch else
    #define throw longjmp(Jump_Buffer, 1)
下面的例程解释如何使用这些宏:
    
    /* 输入一个整型数,如果大于 100,则以异常抛出 */
    #include "stdio.h"
    #include "conio.h"
    #include "setjmp.h"
    jmp_buf Jump_Buffer;
    #define try    if(!setjmp(Jump_Buffer))
    #define catch  else
    #define throw  longjmp(Jump_Buffer, 1)
    int Test(int T);
    int Test_T(int T);
    int Test(int T)
    {
        if(T > 100)    
            throw;
        else
            puts("OK.");
        return;
    }
    int Test_T(int T)
    {
        Test(T);
        return;
    }
    int main(void)
    {
        int T;
        try
        {
            puts("Input a value:");
            scanf("%d", &T);
            T++;
            Test_T(T);
        }
        catch
        {
            puts("Input Error!");
        }
        getch();
        return 0;
    }
    当遇到 throw 抛出异常,立即转跳到 setjmp 处执行,
    屏弃了与之无相关的枝节(函数的返回及 throw 其后的代码)
    main [setjmp()] -> Test_T -> Test [throw]
           ↑                            ↓
           ┗━━━━━━━━━━━━━━┛
    当输入一个大于100的整数,throw 导致异常抛出,使用 1 返回到 setjmp() 函数处,
    宏 try 使 if(!setjmp(Jump_Buffer)) 不成立,执行 catch 块,
    catch 块是十分简单的 else 分支语句关键词的别称。
    这一组宏完成了对 setjmp() 及 longjmp() 两个函数的封装,使程序具备简单的异常处理功能。
    然而,遗憾的是这组宏不具备嵌套的能力,
    当这组宏应用到嵌套异常,只能响应最后一组异常宏,
    并且无法抛出异常类型,至少它连一个常量整型都无法抛出,
    这是因为 jmp_buf 全局只能存放一个 jmpb 结构。
    以下是对上面叙述的简单的图示:
    main()
    {
        try
        {
            Test_T();  ━━━┑
        }                    ┃
        catch                ┃
        {                    ┃
        }                    ┃
    }                        ┃
                             ┃
                             ┃
   Test_T() <━━━━━━━━┛
   {
        try
        {
            Test();  ━━━┑
        }                  ┃
        catch <━━━━━━┿━━━━━┑
        {                  ┃          ┃
        }                  ┃          ┃
    }                      ┃          ┃
                           ┃          ┃(只有最后一组宏可以响应异常)
                           ┃          ┃
    Test()<━━━━━━━━┛          ┃
    {                                  ┃
        if(True)                       ┃
            throw;   ━━━━━━━━━┛
    }
    虽然这组宏无法嵌套使用,然而抛出一个常量整型是有可能的(甚至是一个结构struct),
    更改成如下一组宏,便可抛出一个常量整型,并且可以在 catch 处以 catch(Value)  的方式处理异常。
    jmp_buf Jump_Buffer;
    int     TValue;
    #define try         if( !( TValue = setjmp(Jump_Buffer) ) )
    #define catch(Val)  else if(TValue == Val)
    #define catch_all   else
    #define throw(Val)  longjmp(Jump_Buffer, Val)
    /* throw 抛出的值不应该等于0,因为这会导致无法执行try后面的catch块而继续执行形成了死循环*/
    下面的例程演示了这组宏:
    /* 输入一个整型数值,若大于 100 以异常抛出一个常量 20 
       否则以异常抛出一个常量 20 */
    #include "stdio.h"
    #include "conio.h"
    #include "setjmp.h"
    jmp_buf Jump_Buffer;
    int     TValue;
    #define try         if( !( TValue = setjmp(Jump_Buffer) ) )
    #define catch(Val)  else if(TValue == Val)
    #define catch_all   else
    #define throw(Val)  longjmp(Jump_Buffer, Val)
    int Test(int T);
    int Test_T(int T);
    int Test(int T)
    {
        if(T > 100)
            throw(20);  /*只是演示,20这个常量值并无特别意义*/
        throw(10);      /* catch_all 块将处理这个异常*/
        return;
    }
    int Test_T(int T)
    {
        Test(T);
        return;
    }
    int main(void)
    {
        int T;
        try
        {
            puts("Input a value:");
            scanf("%d", &T);
            T++;
            Test_T(T);
        }
        catch(20)
        {
            puts("Input Error!(Code: 20)");
        }
        catch_all
        {
            puts("Unknown error!");
        }
        getch();
        return 0;
    }
    正是因为 jmp_buf 全局只能存放一个 jmpb 结构,使得只有最后一组宏可以响应异常;
    这是无法嵌套异常的原因,
    要实现多重嵌套可以建立一个全局堆栈来维护一组 jmpb 结构,
    此处不给出实现,若感兴趣请自行实现,文中若有错误,欢迎指正。
    这里给出的只是C异常处理的简单实现,若要完善的异常处理,这需要更多的手段。
[此贴子已经被作者于2006-9-6 16:36:35编辑过]



 
											





 
	    

 
	

