C语言Sigsetjmp函数的用法

1. Sigsetjmp函数
表头文件:#include <setjmp.h>
函数定义:int sigsetjmp(sigjmp_buf env, int savesigs)
函数说明:sigsetjmp()会保存目前堆栈环境,然后将目前的地址作一个记号,而在程序其他地方调用siglongjmp()时便会直接跳到这个记号位置,然后还原堆栈,继续程序的执行。
参数env为用来保存目前堆栈环境,一般声明为全局变量
参数savesigs若为非0则代表搁置的信号集合也会一块保存
当sigsetjmp()返回0时代表已经做好记号上,若返回非0则代表由siglongjmp()跳转回来。
返回:若直接调用则为0,若从siglongjmp调用返回则为非0
实例:
当返回值为0时:
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <signal.h>

#define sigjmp_buf jmp_buf         //为了兼容在win下的编译设置的宏
#define sigsetjmp(env, savemask) setjmp(env)
#define siglongjmp(env, val) longjmp(env, val)

static sigjmp_buf jmpbuf,jumpbuf1;

void sig_fpe(void)
{
   siglongjmp(jumpbuf1, 1);//跳转到sigsetjmp函数并且使得sigsetjmp函数返回值不为0,执行函数内部代码
}

int main(int argc, char *argv[])
{
int i = 0;
int a = 0;
int b = 0;

//    signal(SIGFPE, sig_fpe);
     if ((a = sigsetjmp(jumpbuf1, 1)) == 0) // sigsetjmp返回值为0设置标记成功,
        { 
              int ret = 10 ; //
              printf("ret %d\n",ret);
        }
    else // catch
        { 
             printf("catch exception\n"); // printf("catch excetion\n");
             fflush(stdout);
        } 
     b = sigsetjmp(jmpbuf,1);    //返回值为0,赋值给b
     printf("a = %d, b = %d\n",a,b);
     if(i <= 1) {
    i++;
    sig_fpe();//调用siglongjmp函数
     }
     return 0;
}
结果:
ret 10
a = 0, b = 0
catch exception
a = 1, b = 0
catch exception
a = 1, b = 0

当返回值非0时:
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <signal.h>

#define sigjmp_buf jmp_buf               //为了兼容在win下的编译设置的宏
#define sigsetjmp(env, savemask) setjmp(env)
#define siglongjmp(env, val) longjmp(env, val)

static sigjmp_buf jmpbuf,jumpbuf1;

void sig_fpe(void)
{
   siglongjmp(jumpbuf1, 1);//跳转到sigsetjmp函数并且使得sigsetjmp函数返回值不为0,执行函数内部代码
}

int main(int argc, char *argv[])
{
int i = 0;
int a = 0;
int b = 0;

//    signal(SIGFPE, sig_fpe);
     if ((a = sigsetjmp(jumpbuf1, 1)) != 0) // sigsetjmp返回值为0设置标记成功,
        { 
              int ret = 10 ; //
              printf("ret %d\n",ret);

        } 
    else // catch
        { 
             printf("catch exception\n"); // printf("catch excetion\n");
             fflush(stdout);
        } 
     b = sigsetjmp(jmpbuf,1);    //返回值为0,赋值给b
     printf("a = %d, b = %d\n",a,b);
     if(i <= 1) {
    i++;
    sig_fpe();//调用siglongjmp函数
     }
     return 0;

}
结果:
catch exception
a = 0, b = 0
ret 10
a = 1, b = 0
ret 10
a = 1, b = 0
2. setjmp和longjmp函数

       非局部跳转语句---setjmp和longjmp函数。非局部指的是,这不是由普通C语言goto,语句在一个函数内实施的跳转,而是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。
#include <setjmp.h>
Int setjmp(jmp_buf  env);
       返回值:若直接调用则返回0,若从longjmp调用返回则返回非0值
Void longjmp(jmp_buf env,int val);
        在希望返回到的位置调用setjmp,此位置在main函数中,因为直接调用该函数,所以其返回值为0.setjmp参数evn的类型是一个特殊的类型jmp_buf,这一数据类型是某种形式的数组,其中存放在调用longjmp时能用来恢复栈状态的所有信息。因为需要在另一个函数中引用env变量,所以规范的处理方式是将env变量定义为全局变量。
        当检查到一个错误时,则以两个参数调用longjmp函数,第一个就是在调用setjmp时所用的env,第二个参数是具有非0值的val,它将成为从setjmp处返回的值。使用第二个参数的原因是对于一个setjmp可以有多个longjmp。
使用setjmp和longjmp要注意以下几点:
  1、setjmp与longjmp结合使用时,它们必须有严格的先后执行顺序,也即先调用setjmp函数,之后再调用longjmp函数,以恢复到先前被保存的“程序执行点”。否则,如果在setjmp调用之前,执行longjmp函数,将导致程序的执行流变的不可预测,很容易导致程序崩溃而退出
    2、不要假设寄存器类型的变量将总会保持不变。在调用longjmp之后,通过setjmp所返回的控制流中,程序中寄存器类型的变量将不会被恢复。寄存器类型的变量,是指为了提高程序的运行效率,变量不被保存在内存中,而是直接被保存在寄存器中。寄存器类型的变量一般都是临时变量,在C语言中,通过register定义,或直接嵌入汇编代码的程序。这种类型的变量。
       longjmp必须在setjmp调用之后,而且longjmp必须在setjmp的作用域之内。具体来说,在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到 setjmp的下一条语句执行。实际上setjmp函数将发生调用处的局部环境保存在了一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放 (函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值