异想天开

What's the true meaning of light, Could you tell me why

c语言的setjmp和longjmp

日期:2015-07-08 16:47:13
  
最后更新日期:2015-10-04 12:22:01
c语言中,若嵌套调用很多层函数,发生了非致命错误,这个时候不会调用exit退出程序,那么一层层返回,交给上层调用函数检测返回值的做法比较费时。c语言里面有个setjmp和longjmp机制,可以返回到函数调用路径中的某一个函数中。
[code lang="cpp"]
#include <setjmp.h>
int setjmp(jmp_buf env);
int longjmp(jmp_buf env, int val);
[/code]
在期望返回到函数某一的位置调用setjmp,后面的longjmp将会再次从该函数返回。不过第一次setjmp返回的值是0,后面出错利用longjmp返回,这时setjmp返回值是longjmp函数参数中设置的val。通过设置不同的val,我们可以区分不同的出错情况。
请看下例:
[code lang="cpp"]
//test.c
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>

static void f1(int, int, int, int, int);

jmp_buf jmpbuffer;
static int globval;

int main(){
int autoval;
register int regival;
volatile int volaval;
static int statval;

globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;
if (setjmp(jmpbuffer) != 0){
printf("after longjmp:\n");
printf("globval=%d, autoval=%d, regival=%d, volaval=%d, statval=%d\n",\
globval,autoval,regival,volaval,statval);
exit(0);
}

//改变值
globval=95; autoval=96; regival=97; volaval=98; statval=99;
f1(globval, autoval, regival, volaval, statval);
exit(0);
return 0;
}

static void f1(int i, int j, int r, int k, int l)
{
printf("in f1():\n");
printf("globval=%d, autoval=%d, regival=%d, volaval=%d, statval=%d\n",\
i,j,r,k,l);
longjmp(jmpbuffer,1);
}
[/code]

探讨两个问题
1.自动变量,寄存器变量,和易失变量
这里执行longjmp后,有点类似于“回滚”。变量的状态怎么办?上面的例子,分别用全局变量,自动变量,寄存器变量,易失变量,静态变量测试。大多数系统实现不会回滚自动变量,寄存器变量,手册上面说它们的值是不确定的。如果你有一个自动变量,不想其值回滚,那么可以申明为volatitle属性,申明为全局和静态的变量,longjmp后保持不变。
上诉程序分别使用不带优化选项和带优化选项进行编译,运行它们得到的结果是不一样的。
[code lang="cpp"]
不带优化选项(gcc -Wall test.c -o testout)执行结果:
in f1():
globval=95, autoval=96, regival=97, volaval=98, statval=99
after longjmp:
globval=95, autoval=96, regival=97, volaval=98, statval=99
带优化选项(gcc -Wall test.c -O3 -o testout)执行结果:
in f1():
globval=95, autoval=96, regival=97, volaval=98, statval=99
after longjmp:
globval=95, autoval=2, regival=3, volaval=98, statval=99
[/code]

2.会不会存在,在一个函数调用链里面存在两个可以返回的setjmp?
猜测应该是不会的,每次setjmp都需要利用一个jmp_buf,而后面longjmp还是利用相同的jmp_buf。一一对应的关系。
注:
对于这些跳转,资源的回收与释放需要注意。