setjmp&longjmp

有时候,当接收到一个信号时,希望能跳回程序中以前的一个位置执行。例如,在有

的程序内,当用户按了中断键,则程序跳回到显示主菜单执行。我们可以用库系统调用

setjmp()和longjmp()来完成这项工作。setjmp()能保存程序中的当前位置(是通过保存堆栈

环境实现的),longjmp()能把控制转回到被保存的位置。在某种意义上,longjmp()是远程跳

转,而不是局部区域内的跳转。我们必须注意到,由于堆栈已经回到被保存位置这一点,

所以longjmp()从来不返回。然而,与其对应的setjmp()是要返回的。

setjmp()和longjmp()在setjmp.h 中的定义分别如下:

int setjmp(jmp_buf env);

void longjmp(jmp_buf env, int val);

setjmp()只有一个参数env,用来保存程序当前位置的堆栈环境。而longjmp()有两个参

数:

参数env 是由setjmp()所保存的堆栈环境。

参数val 设置setjmp()的返回值。longjmp()本身是没有返回的,但其执行后跳转到保存

env 参数的setjmp()调用,并由setjmp()调用返回,就好像程序刚刚执行完setjmp()一样,此

时setjmp()的返回值就是val。但是要注意的是,longjmp()调用不能使setjmp()调用返回0,

如果val 为0,则setjmp()的返回为1。

下面的例子演示了setjmp()和longjmp()的使用:

#include <stdio.h>

#include <setjmp.h>

#include <signal.h>

jmp_buf position;

main()

{

int goback();

/* 保存当前的堆栈环境 */

setjmp(position);

signal(SIGINT,goback);

domenu();

}

goback()

{

fprintf(stderr,”\nInterrupted\n”);

/* 跳转回被保存的断点 */

longjmp(position,1);

}

 #include <setjmp.h>

  int setjmp(jmp_buf env);

Returns: 0 if called directly, nonzero if returning from a call to longjmp

  void longjmp(jmp_buf env, int val);


       setjmp(j)设置“ jump”点,用正确的程序上下文填充jmp_buf 对象j。这个上下文包括程序存放位置、栈和框架指针,其它重要的寄存器和内存数据。当初始化完jump 的上下文,setjmp()返回0 值。 setjmp 函数的调用时,会保存程序当前的堆栈环境到 env 参数中;
            以后调用 longjmp(j,r)的效果就是一个“长跳转”到由j 描述的上下文处(也就是到那原来设置j 的setjmp()处)。当作为长跳转的目标而被调用时,setjmp()返回r 或1(如果r 设为0 的话)。(记住,setjmp()不能在这种情况时返回0。
  
             通常 , 用longjmp()来终止异常,用setjmp()标记相应的异常处理程序,  在调用 setjmp 的函数返回之前,调用 longjmp ,否则结果不可预料。
  在使用 longjmp 时,请遵守以下规则或限制:
    不要假象寄存器类型的变量将总会保持不变。在调用 longjmp 之后,通过 setjmp 所返回的控制流中,例程中寄存器类型的变量将不会被恢复。
    不要使用 longjmp 函数,来实现把控制流,从一个中断处理例程中传出,除非被捕获的异常是一个浮点数异常。在后一种情况下,如果程序通过调用 _fpreset 函数,来首先初始化浮点数包后,它是可以通过 longjmp 来实现从中断处理例程中返回。
     C++ 程序中,小心对 setjmp longjmp 的使用,应为 setjmp longjmp 并不能很好地支持 C++ 中面向对象的语义。因此在 C++ 程序中,使用 C++ 提供的异常处理机制将会更加安全。 
   #include   <conio.h>  
  #include   <setjmp.h>  
  void   RaiseException ( jmp_buf   jmpbuf)  
  {  
    printf(   "Press   a   key   to   restore   stack   environment...\n"   )   ;  
    getch()   ;  
    longjmp(jmpbuf, 1);  
}  
 
  int   main()  
  {  
    jmp_buf   jmpbuf   ;  
int   result  ;  
 
     printf(   "Save   stack   environment...\n"   )   ;  
     result   =   setjmp(jmpbuf)   ;  
if( result  ==   0  )  
{
 //Do something
 //If anything wrong.
 RaiseException(jmpbuf)  ;  
}
else// the exception handler, return by longjump, non-zero value
{  
         printf(   "longjump()   returned   %d.\n",   result   )   ;  
         exit(0)   ;  
}
  
    return   0   ;  
  }  
  程序输出将是如下序列: 
  Saving   stack   environment...  
  Call   MyFunc()...  
  Press   a   key   torestore   stack   environment...  
setjmp()   returned   1
//Example 2
#include <stdio.h>
#include <setjmp.h>
 
jmp_buf save;
 
void main()
{
 char c;
 
 for (;; )
{
    switch ( setjmp( save )) 
{
     case 0:
printf ( "Zero returned from setjmp on setup.\n\n");   
break;              
     case 1:
printf ( "NORMAL PROGRAM OPERATION\n\n" );     
break;
     case 2:
printf ( "WARNING\n\n" );     
break;
     case 3:
 printf ( "FATAL ERROR PROGRAM TERMINATED\n\nReally Terminate? y/n: " );
                        fflush ( stdout );           
                        scanf ( "%1s", &c );
                       c  = tolower ( c );       
if ( c == 'y' ) return ( 1 );
                          printf ( "\n" );       break;
        default:     
printf ( "Should never return here.\n" );     
break;
    }
    process ();
 }
}
 
void process ()
{
 int i;
 
 printf ( "Input a number to simulate an error condition: " );
 fflush ( stdout ); scanf ( "%d", &i ); i %= 3;
 i++;               
 longjmp ( save, i);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值