您的位置:首页 > 其它

setjmp和longjump 用法

2016-07-21 10:03 429 查看
与abort()和exit()相比,goto语句看起来是处理异常的更可行方案。goto是本地的,它只能跳到所在函数内部的标号上,而不能将控制权转移到所在程序的任意地点.为了解决这个限制,C函数库提供了setjmp()和longjmp()函数,它们分别类似于非局部标号和goto作用。

头文件 setjmp.h 申明了这些函数及jmp_buf数据类型。

原理非常简单:

1:setjmp(jump)设置“jump”点,用正确的程序上下文填充jmp_buf对象jump.这个上下文包括程序指针、栈指针,其它重要的寄存器和内存数据。当初始化完jump的上下文,setjmp()返回0值。

2:以后调用longjmp(jump,r)的效果就是一个非局部的goto或“长跳转”到由jump描述的上下文处(也就是到那原来设置jump的setjmp()处)。当作为长跳转的目标而被调用时,setjmp()返回r或1(如果r设为0的话),(setjmp()不能在这种情况时返回0)

通过两类返回值,setjmp()让你知道它正在被怎么使用。当设置jump时,setjmp()如你期望地执行;但当作为长跳转的目标时,setjmp()就从外面“唤醒”它的上下文。你可以用longjmp()来终止异常,用setjmp()标记相应的异常处理程序。

#include <setjmp.h>
#include <stdio.h>

jmp_buf j;
void raise_exception(void)
{
printf("exception raised\n");
longjmp(j, 1); /* jump to exception handler */
printf("this line should never appear\n");
}

int main(void)
{
if (setjmp(j) == 0)
{
printf("''setjmp'' is initializing ''j''\n");
raise_exception();
printf("this line should never appear\n");
}
else
{
printf("''setjmp'' was just jumped into\n");
/* this code is the exception handler */
}
return 0;
}


上边程序在调用longjump 时,就跳转到setjump处再次执行setjump,这时setjump返回非0值,从而执行else分支。

jmp_buf j;
void f(void)
{
setjmp(j);
}
int main(void)
{
f();
longjmp(j, 1); /* logic error */
return 0;
}


上边代码会报Segmentation fault (core dumped),这是由于执行f()函数时,setjmp会保存当前上下文,但是栈指针是当前f()函数中的,当f()返回时,会出栈,这时栈指针是相对main()的,这个时候调用longjump就将之前相对f()栈指针设置为main()函数栈指针,从而栈被dirt,虽然程序指针是对的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: