C语言中,在一个函数中执行跳转,我们使用goto语句。而执行从一个函数跳转到另一个函数,我们使用setjmp和longjmp函数的组合。
include <setjmp.h>
Int setjmp(jmp_buf env);
返回值:若直接调用则返回0,若从longjmp调用返回则返回非0值
Void longjmp(jmp_buf env,int val);
使用方法
我们在希望返回的位置调用setjmp,此位置在main函数中,因为直接调用该函数,所以其返回值为0。setjmp参数env的类型是一个特殊的类型jmp_buf,这一数据类型是某种形式的数组,其中存放在调用longjmp时能用来恢复栈状态的所有信息。因为需要在另一个函数中引用env变量,所以规范的处理方式是将env变量定义为全局变量。
当检查到一个错误时,则以两个参数调用longjmp函数,第一个就是在调用setjmp时所用的env,第二个参数是具有非0值的val,它将成为从setjmp处返回的值。使用第二个参数的原因是对于一个setjmp可以有多个longjmp。
通俗的解释就是:先调用setjmp,用变量envbuf记录当前的位置,然后调用longjmp,返回envbuf所记录的位置,并使setjmp的返回值为val。当时用longjmp时,envbuf的内容被销毁了。其实这里的“位置”一词真正的含义是栈定指针。
longjmp 是不直接返回的,而是从 setjmp 函数中返回,longjmp 执行完之后,程序就像刚从 setjmp 函数返回一样。
一个简单的实例
#include<stdio.h>
#include<setjmp.h>
jmp_buf buf;
void hello()
{
printf("hello\n");
longjmp(buf,1);
printf("you will see this\n");
}
main()
{
if(setjmp(buf)==0)
{
printf("first \n");
hello();
}
else
printf("ok\n");
}
该函数的输出是
first
hello
ok
setjmp与longjmp结合使用时,它们必须有严格的先后执行顺序,也即先调用setjmp函数,之后再调用longjmp函数,以恢复到先前被保存的“程序执行点”。否则,如果在setjmp调用之前,执行longjmp函数,将导致程序的执行流变的不可预测,很容易导致程序崩溃而退出。