c语言中的函数间的跳转函数setjmp和longjmp

       原创文章,转载请注明出处,谢谢!       
       作者:清林,博客名:飞空静渡

 

我们知道,在c语言中我们可以使用goto语句在一个函数中进行跳转,例如一个常用的goto方式为:

 

......

//分配资源

......

 

if error1

   goto error;

 

if error2

   goto error;

 

........

error:

    ......

    // 释放资源

    ......

 

但是goto语句也只限于一个函数内,不能进行函数间的跳转。在c语言中,进行函数间的跳转使用setjmp和longjmp函数。

为什么要有个函数间的跳转呢,这是因为,如果我们在调用函数时,函数的调用的嵌套的层次很深的话,如果出错,那么一层一层的返回和判断就很麻烦,所以,如果出错,就可以直接返回到最上面的调用的函数就会很方便。

 

我们来看一下这两个函数怎么使用,首先看一下这两个函数的原型:

#include <setjmp.h>

 

int setjmp(jmp_buf env);   //直接调用则返回0,如从longjmp调用则返回非0

int longjmp(jmp_buf env, int val);

jum_buf是一个类型,其中env存储了一些longjmp调用返回用来恢复栈状态的所有信息。longjmp中的env和setjmp中的env是同一个。val是程序员自定义的直,这个值用在setjmp的返回值中,这样我们就可以知道是在哪个的longjmp跳转回来的。另外,由于在不同的函数间调用setjmp和longjmp,而这两个函数要公用一个env变量,所以把env定义为一个全局变量。

 

下面我们看一个简单的例子:

 

编译:gcc main.c

运行:./a.out

输出:

in main function!
in func1 function!
in func2 function!
get the error from jump return!

 

我们在程序中可以看到,我们在main函数用setjmp中设置了一个接受跳转返回的点,在func2函数中用longjmp跳转返回。

在跳转返回后,我们直接退出函数,那么后面的

    printf("main function end!/n");
    return 0;
这两个语句将得不到执行。

 

前面我们说过longjmp函数中的val参数用来確定我们的jump是在哪产生的,下面我们修改一下前面的例子,看看怎样区别不同的跳转点。

 

编译:gcc main.c

运行:./a.out

输出:

in main function!
in func1 function!
get the error from func1 function !

 

注意:不可这样

if(setjmp(jmpbuff) == 1)

  ........

if(setjmp(jmpbuff) == 2)

  ........

这样会在main中设置两个跳转返回点,而且是同一个jmpbuff,那么前面一个会被后面一个覆盖,则用func1中的跳转返回点就是后面的那个,在main函数中就会比较返回值是否为2,因为在func1中跳转返回是1,因此会再次执行后面的func1函数,那么就会陷入死循环中了。

 

我们知道,在一个进程中,当我们调用一个函数时,我们的进程就会在栈中分配一个新栈区给这个函数,当这个函数返回时,就销毁这个栈区。

因此,当我们进行函数间的跳转时,我们上层的函数的某些变量的值是得不到保存的。我们可以看下是哪些变量受到影响。

我们修改第一个例子:

 

第一次,我们尝试不优化编译:

编译:gcc main.c

运行:./a.out

输出:

in func1 function!
globVal = 101, autoVal = 102, regiVal = 103, volaVal = 104, statVal = 105
in func2 function!
get the error from jump return!
globVal = 101, autoVal = 102, regiVal = 103, volaVal = 104, statVal = 105

 

第二次,我们进行优化编译:

编译:gcc -O main.c

运行:./a.out

输出:

in func1 function!
globVal = 101, autoVal = 102, regiVal = 103, volaVal = 104, statVal = 105
in func2 function!
get the error from jump return!
globVal = 101, autoVal = 2, regiVal = 3, volaVal = 104, statVal = 105

 

我们可以看到,全局、静态和易失性变量不受优化的影响,它们的值是最近变化的值。这也告诉我们如果我们写一个非局部跳转的程序,就应该使用volatile属性的变量。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值