C语言传统的错误处理方式setjmp与longjmp

    setjmp和longjmp是C语言独有的,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,按照程序员的预先设计的意图,去实现对程序中可能出现的异常进行集中处理。处理方式是:在调用setjmp()时把当前的堆栈环境保存到jmp_buf(一个结构体类型,下面简单介绍)类型的env中,以后调用longjmp()函数还原所保存的环境并将控制权返回给setjmp之后的调用点。关于这点,《C++编程思想》是这样解析的:使用setjmp()可以在程序中保存一个已知的无错误的状态,一旦发生错误,就可以通过调用longjmp()返回到该状态。同样,这使得错误发生的位置与保存状态的位置之间产生高度的耦合。

jmp_buf结构体介绍:

    在setjmp.h里的定义是:typedef struct _jmp_buf { int _jb[_JBLEN + 1]; } jmp_buf[1];  

setjmp()函数介绍:

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

longjmp()函数介绍:

    longjmp函数是还原堆栈环境和执行区域设置的。其原型是:void longjmp(jmp_buf env,  int  value );参数:env  环境中储存的变量   value  是作为跳到setjmp的调用点时,setjmp()函数的一个返回值。例如下面的例子中,由于longjmp(kansas, 47); 所以,跳到setjmp()时,setjmp必须返回47这个值。

 

对于学习C++的朋友,有一点需要强调的是:由于setjmp()与longjmp()是属于C语言的函数,所以在C++的错误处理方式中,这两个函数并不会去调用析构函数,所以,当跳过了对象的析构操作时,先前产生的对象就会被正确清理掉(因为longjmp()函数可跳转到析构函数的作用范围以外的地方,这使得程序的行为存在不可预料的情况,对程序而言这绝对是有害的)。

 

代码如下:

#include <iostream>
#include <csetjmp>
using namespace std;

class NewChange
{
public:
 NewChange(){cout<<"NewChange()"<<endl;}
 ~NewChange(){cout<<"~NewChange()"<<endl;}
};

jmp_buf value;

void oz()
{
    NewChange rb;
 for(int i = 0; i<3; i++)
  cout<<"You are strange!"<<endl;
 longjmp(value, 4);
}

int main()
{
 /*setjmp()第一次初始化时,把当前处理器的状态信 **
 **息保存到jmp_buf中去并返回0,当由于longjmp的调用**
 **使执行点跳回到这里时,setjmp就返回longjmp函数的**
 **第二个参数4*/
    if(setjmp(value)==0)  
 {
     cout<<"I am just ..."<<endl;
  oz();
 }
 else
 {
     cout<<"I had the strangest dream..."<<endl;
 }
 return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值