调用setjmp()和longjmp()处理异常

发表于:2015年4月21日 00:28  分类:c 719次浏览

C语言没有像C++、Java等面向对象语言的try/catch异常处理模块,如果要在C中对异常进行处理,我通常给可能产生异常的函数返回值中加个错误代码,if条件判断函数返回值,在if代码块中处理异常,但是这样有一个致命的缺陷:异常处理前后的寄存器状态发生了改变,可能导致后续代码调用的错误。

如果能够解决这个问题,在异常处理前保存运行时堆栈,处理完毕恢复堆栈,就可以将异常处理从主程序中剥离开来,分别考虑。通过查看C标准库,我发现setjmp()和longjmp()这两个函数正好满足这个要求:它们俩声明在setjmp.h头文件中,负责非局部跳转,当需要跳转到非同一个函数的地方时就需要用到setjmp和longjmp,setjmp函数用于保存程序的运行时的堆栈环境,接下来的其它地方,可以通过调用longjmp函数来恢复先前被保存的程序堆栈环境,利用这个性质,可以方便的添加异常处理代码,并且不影响主程序的堆栈调用。

#include <stdio.h>
#include <setjmp.h>
jmp_buf j;
void Exception(void)
{
	longjmp(j,1);
}
double diva(double num1,double num2)         
{
	double re;
	re=num1/num2;
	return re;
}
 int main()
{
	double a,b,result;
	printf("请输入第一个数字:");
	scanf("%lf",&a);
	printf("请输入第二个数字:");
	if(setjmp(j)==0)
	{
		scanf("%lf",&b);
		if(0==b)
			Exception();
		result=diva(a,b);
		printf("相除的结果是: %.2lf\n",result);
	}
	else
	{
		printf("试图除以一个为0的数字\n");
	}
	return 0;
}

上面的程序对除零异常进行处理,首先进入if语句,setjmp函数将程序状态保存在全局变量j中,因为是第一次调用setjup,所有setjmp函数返回0,进入if语句块:等待用户输入第二个参数(这一步骤会产生异常);如果输入了0,紧接着调用异常处理函数Exception,对异常进行处理,最后在函数返回前调用longset,将j中存储的堆栈状态恢复,程序返回到了setjump处;此时,第二次调用setjmp,它会返回一个非零值,跳转到else语句,打印”试图除以一个为0的数字\n”。

需要注意的是,在调用setjmp()和longjmp()处理异常的过程中,因为恢复了程序的状态,所以期间的动态内存分配会失效,无法使用malloc和calloc函数,着在一定方面上降低了程序的灵活性。

发表评论

电子邮件地址不会被公开。 必填项已用*标注