关于setjmp和longjmp函数

setjmp()和longjmp()函数的用途
因为它们是通过操纵过程活动记录实现的。许多程序员新手并不知道这个强大的机制,因为它是C语言所独有的。它们部分弥补了 C语言有限的转移能力。这两个函数是协同工作的,如下所示;

  1. setjmp(jmp_buf j)必须首先被调用。它表示使用变量j记录现在的位置,函数返回零。
  2. longjmp(jmp_buf j, int i)可以接着被调用。它表示“回到j所记录的位置,让它看上去像是从原先的setjmp()函数返回一样。但是函数返回i,使代码能够知道它是实际上是通过 longjmp()返回的。
    当使用于longjmp()时, j的内容被销毁

setjmp()保存了一份程序的计数器和当前的栈顶指针。如果喜欢也可以保存一些初始值。longjmp恢复这些值,有效地转移控制并把状态重置回保存状态的时候。这被称作“展开堆栈(unwinding stack)",因为你从堆栈中展开过程活动记录,直到取得保存在其中的值。尽管 longimp会导致转移,但它和goto又有不同,区别如下:

  1. goto语句不能跳出C语言当前的函数(这也是"longjmp"取名的由来,它可以跳得很远,甚至可以跳到其他文件的函数中)。
  2. 用longimp只能跳回到曾经到过的地方。在执行setjmp的地方仍留有一个过程活动记录。从这个角度讲, longjmp更像是“从何处来(come from)“而不是“往哪里去(go to)”. longjmp接受一个额外的整型参数并返回它的值,这可以知道是由longjmp转移到这里的还是从上条语句执行后自然而然来到这里的

下面的代码显示了setjmp()和longjmp()函数的用法:

#include<setjmp.h>
#include<stdio.h>
jmp_buf buf;

void banana()
{
	printf("in banana()\n");
	longjmp(buf,1);
	printf("you'll never see this,because i longjmp'd\n");
}
int main()
{
	if(setjmp(buf))
		printf("back in main\n");
	else
	{
		printf("first time through\n");
		banana();
	}
	return 0;
}

其结果为:
在这里插入图片描述
需要注意的地方是:
保证局部变量在longjmp过程中一直保持它的值的惟一可靠方法是把它声明为volatile (这适用于那些值在setjmp执行和longjmp返回之间会改变的变量)。setjmp/longjmp最大的用途是错误恢复。只要还没有从函数中返回,一旦发现一个不可恢复的错误,可以把控制转移到主输入循环,并从那里重新开始。有些人使用setjmp/longjmp从一串无数的函数调用中立即返回。还有一些人用它们防范潜在的危险代码,例如,当对下面例子中的可疑指针进行解除引用操作时:

switch (setjmp(jbuf))
{
	case 0: apple = *suspicious;break;
	case 1: printf("suspicious is a bad points\n");break;
	default: die("unexpected value returned by setjmp");
}

这里需要一个处理程序来处理段违规信号,后者进行相应的longjmp(jbuf, 1)操作.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值