http://yijiuzai.blog.163.com/blog/static/10375672720105197114165/
我们知道,在c语言中我们可以使用goto语句在一个函数中进行跳转,例如一个常用的goto方式为:
......
//分配资源
......
if error1
goto error;
if error2
goto error;
........
error:
......
// 释放资源
......
但是goto语句也只限于一个函数内,不能进行函数间的跳转。在c语言中,进行函数间的跳转使用setjmp和longjmp函数。
为什么要有个函数间的跳转呢,这是因为,如果我们在调用函数时,函数的调用的嵌套的层次很深的话,如果出错,那么一层一层的返回和判断就很麻烦,所以,如果出错,就可以直接返回到最上面的调用的函数就会很方便。
我们来看一下这两个函数怎么使用,首先看一下这两个函数的原型:
#include <setjmp.h>
int setjmp(jmp_buf env); //直接调用则返回0,如从longjmp调用则返回非0
int longjmp(jmp_buf env, int val);
jum_buf是一个类型,其中env存储了一些longjmp调用返回用来恢复栈状态的所有信息。longjmp中的env和setjmp中的env是同一个。val是程序员自定义的直,这个值用在setjmp的返回值中,这样我们就可以知道是在哪个的longjmp跳转回来的。另外,由于在不同的函数间调用setjmp和longjmp,而这两个函数要公用一个env变量,所以把env定义为一个全局变量。
下面我们看一个简单的例子:
view plaincopy to clipboardprint?
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuffer;
void func1();
void func2();
int main(void)
{
printf("in main function! ");
if(setjmp(jmpbuffer) != 0)
{
printf("get the error from jump return! ");
return -1;
}
func1();
printf("main function end! ");
return 0;
}
void func1()
{
printf("in func1 function! ");
func2();
}
void func2()
{
printf("in func2 function! ");
longjmp(jmpbuffer, 1);
}
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuffer;
void func1();
void func2();
int main(void)
{
printf("in main function! ");
if(setjmp(jmpbuffer) != 0)
{
printf("get the error from jump return! ");
return -1;
}
func1();
printf("main function end! ");
return 0;
}
void func1()
{
printf("in func1 function! ");
func2();
}
void func2()
{
printf("in func2 function! ");
longjmp(jmpbuffer, 1);
}
编译:gcc main.c
运行:./a.out
输出:
in main function!
in func1 function!
in func2 function!
get the error from jump return!
我们在程序中可以看到,我们在main函数用setjmp中设置了一个接受跳转返回的点,在func2函数中用longjmp跳转返回。
在跳转返回后,我们直接退出函数,那么后面的
printf("main function end! ");
return 0;
这两个语句将得不到执行。
前面我们说过longjmp函数中的val参数用来確定我们的jump是在哪产生的,下面我们修改一下前面的例子,看看怎样区别不同的跳转点。
view plaincopy to clipboardprint?
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuffer;
void func1();
void func2();
int main(void)
{
printf("in main function! ");
int errNum = 0;
errNum = setjmp(jmpbuffer);
if(errNum != 0)
{
if (errNum == 1)
printf("get the error from func1 function ! ");
if (errNum == 2)
printf("get the error from func2 function ! ");
return -1;
}
func1();
printf("main function end! ");
return 0;
}
void func1()
{
printf("in func1 function! ");
longjmp(jmpbuffer, 1);
func2();
}
void func2()
{
printf("in func2 function! ");
longjmp(jmpbuffer, 2);
}
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuffer;
void func1();
void func2();
int main(void)
{
printf("in main function! ");
int errNum = 0;
errNum = setjmp(jmpbuffer);
if(errNum != 0)
{
if (errNum == 1)
printf("get the error from func1 function ! ");
if (errNum == 2)
printf("get the error from func2 function ! ");
return -1;
}
func1();
printf("main function end! ");
return 0;
}
void func1()
{
printf("in func1 function! ");
longjmp(jmpbuffer, 1);
func2();
}
void func2()
{
printf("in func2 function! ");
longjmp(jmpbuffer, 2);
}