当 setjmp 和 longjmp 一起使用时,它们提供了一种执行非本地 goto
的方法。 它们通常在 C 代码中用于将执行控制传递给先前调用的例程中的错误处理或恢复代码,而不使用标准调用或返回约定。
由于 setjmp
和 longjmp
不支持在 C++ 编译器之间以可移植的方式正确销毁堆栈帧对象,并且它们可能会因阻止优化局部变量而降低性能,因此不建议在 C++ 程序中使用。 建议改用 try
和 catch
构造。
abort函数和exit函数的直接退出非常直接,goto语句使用起来更温柔。但是goto是本地的,它只能跳到所在函数内部的标号上,而不能将控制权转移到所在程序的任意地点。
为了解决这个限制,C函数库提供了setjmp函数和longjmp函数,它们分别承担非局部标号和goto作用。需要包含头文件<setjmp.h>,在其中申明了这些函数及的jmp_buf数据类型。
原理:
1. setjmp(j)设置“jump”点<goto>,用正确的程序上下文填充jmp_buf对象j(static jmp_buf j)。这个上下文包括程序存放位置、栈和页框指针,其它重要的寄存器和内存数据。当初始化完jump的上下文,setjmp函数返回0值。
2.以后调用longjmp(j,n)的效果就是一个非局部的goto或“长跳转”到由j描述的上下文处(也就是到那原来设置j的setjmp函数处)。当作为长跳转的目标而被调用时,setjmp()返回n或1,(setjmp函数不能在这种情况时返回0)。
通过不同的返回值,setjmp函数让你知道它当前使用情况。当设置j时,setjmp函数如你期望地执行即返回0;但当作为长跳转的目标时,setjmp函数就从外面“唤醒”它的上下文。你可以用longjmp函数来终止异常,用setjmp函数标记相应的异常处理程序。
#include <setjmp.h>
#include <stdio.h>
static jmp_buf j;
void __exception(void)
{
printf("Show exception.\n");
longjmp(j, 1); /* jump to exception handler case 1 */
printf("This line will never be appeared.\n");
}
int main(void)
{
switch (setjmp(j)) {
case 0:
printf("''setjmp'' initialization.\n");
__exception();
printf("This line will be never appeared.\n");
break;
case 1:
printf("Deal with exception branch.\n");break;
default:
break;
}
return 0;
}