我们都知道在一个函数内进行跳转,可以使用goto语句,但是如果要在函数之间跳转goto是不能完成的。要想完成函数之间的跳转我们需要借助setjmp和longjmp这两个函数连实现,这都包含在头文件setjmp.h中
函数原型:
1. int setjmp(jmp_buf env):此函数的功能是将函数在此处的上下文保存在jmp_buf结构体中,以供longjmp从此结构体中恢复。参数env即为保存上下文的jmp_buf结构体变量。如果直接调用该函数返回值为0,若该 函数从longjmp调用返回,返回值为非零,用longjmp函数提供。通过该返回值,我们可以判定setjmp是第一次调用还是从其他地方跳转过来的。
2.void longjmp(jmp_buf env, int val):此函数的功能是从jmp_buf结构体中恢复由setjmp函数保存的上下文。该函数不返回,而是从setjmp函数返回(longjmp不直接返回,而是从setjmp函数中返回,longjmp执行完后,程序就像是从setjmp函数返回一样)。参数env是由setjmp函数保存过的上下文,参数val表示从longjmp函数传递给setjmp函数的返回值,如果val值为0,setjmp将返回1,否则返回val。
例如:
http://en.wikipedia.org/wiki/Setjmp.h
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
http://www.cnblogs.com/hazir/p/c_setjmp_longjmp.html
函数原型:
1. int setjmp(jmp_buf env):此函数的功能是将函数在此处的上下文保存在jmp_buf结构体中,以供longjmp从此结构体中恢复。参数env即为保存上下文的jmp_buf结构体变量。如果直接调用该函数返回值为0,若该 函数从longjmp调用返回,返回值为非零,用longjmp函数提供。通过该返回值,我们可以判定setjmp是第一次调用还是从其他地方跳转过来的。
2.void longjmp(jmp_buf env, int val):此函数的功能是从jmp_buf结构体中恢复由setjmp函数保存的上下文。该函数不返回,而是从setjmp函数返回(longjmp不直接返回,而是从setjmp函数中返回,longjmp执行完后,程序就像是从setjmp函数返回一样)。参数env是由setjmp函数保存过的上下文,参数val表示从longjmp函数传递给setjmp函数的返回值,如果val值为0,setjmp将返回1,否则返回val。
例如:
#该程序运行的结果为:
i = 0
i = 2
在c语言中没有像java、c#等面向对象语言的异常处理机制,但是我们同样可以使用setjmp和longjmp这两个函数来模拟实现该功能。
例如:
#include <stdio.h>
#include <setjmp.h>
#define TRY do{ jmp_buf ex_buf__; switch( setjmp(ex_buf__) ){ case 0: while(1){
#define CATCH(x) break; case x:
#define FINALLY break; } default:
#define ETRY } }while(0)
#define THROW(x) longjmp(ex_buf__, x)
#define FOO_EXCEPTION (1)
#define BAR_EXCEPTION (2)
#define BAZ_EXCEPTION (3)
int
main(int argc, char** argv)
{
TRY
{
printf("In Try Statement\n");
THROW( BAR_EXCEPTION );
printf("I do not appear\n");
}
CATCH( FOO_EXCEPTION )
{
printf("Got Foo!\n");
}
CATCH( BAR_EXCEPTION )
{
printf("Got Bar!\n");
}
CATCH( BAZ_EXCEPTION )
{
printf("Got Baz!\n");
}
ETRY;
return 0;
}
参考资料
http://en.wikipedia.org/wiki/Setjmp.h
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
http://www.cnblogs.com/hazir/p/c_setjmp_longjmp.html