1//所需头文件
2#include <setjmp.h>
3
4int setjump(jmp_buf buf)
5void longjump(jmp_buf buf, int i)
6
下面,我们来看看这两个函数到底有什么可以推敲的东西。
1、函数介绍
有研究过RTOS的朋友应该对此不难理解,setjump主要是保存当前函数调用点的现场环境(或者叫上下文),比如各种寄存器、堆栈等等,那么这些环境信息就记录在jmp_buf所定义的buf中。
而当我们在其他位置调用longjump函数就相当于一个长跳转,传入之前保存在buf中的信息,即可跳回到之前setjump所调用的位置(理解为恢复setjump所保存的环境也是可以的)。
所以,这里值得注意的是,不要率先调用longjump,否则程序不知道飞去哪里了。
其实跟RTOS中进行任务切换有着异曲同工之妙。
你大概已经注意到setjump有一个返回值,其主要分为两种情况:
当直接调用setjump函数,则返回0;
当调用longjump跳转到setjump位置,则其返回longjump的第二个非零参数。
2、跟goto有啥区别?
在C语言中goto只能实现函数内部的跳转,无法实现跨函数的直接跳转,比如函数嵌套多层的跳转等等。
当然,你也可以借助goto与函数返回配合完成函数之间的跳转,不过那太麻烦了,所以这两个库函数该派上用场了。
这样的跳转太过于霸道,我们还是限制一下,切不可滥用,但其为异常处理代码的模块化带来了福音,在非常多的开源库中都有实际应用。
下面给大家一个参考示例 :
1#include <stdio.h>
2#include <setjmp.h>
3
4jmp_buf mark;
5int fperr;
6void fpcheck(void);
7
8/*********************************************
9 * Function: main
10 * Description : 主任务函数
11 * Note:(公众号:最后一个bug)
12 *********************************************/
13int main( void )
14{
15 int jmpret;
16
17 //记录异常代码与正常代码分支位置
18 jmpret = setjmp(mark);
19 if( jmpret == 0 )
20 {
21 //正常用户程序运行
22
23 }
24 else
25 {
26 //在正常用户程序运行过程中发生异常
27 fpcheck();
28 }
29}
30/*********************************************
31 * Function: Errorhandler
32 * Description : 异常中断,在正常用户程序运行过程中发生异常处理函数
33 * Note:(公众号:最后一个bug)
34 *********************************************/
35void Errorhandler(void)
36{
37 fperr = num;
38 longjmp( mark, -1 ); //进行长跳转到异常处理
39}
40
41/*********************************************
42 * Function: fpcheck
43 * Description : 故障处理函数
44 * Note:(公众号:最后一个bug)
45 *********************************************/
46void fpcheck(void)
47{
48
49 switch( fperr )
50 {
51 case INVALID:
52 //user Code
53 break;
54
55 case OVERFLOW:
56 //user Code
57 break;
58
59 case ZERODIVIDE:
60 //user Code
61 break;
62 default:
63 break;
64 }
65
66}
3、局限性
这组函数除了前面介绍的注意事项,还有一个非常值得注意的点就是longjump的调用时机必须在setjump被调用的所在函数返回前。
因为setjump保存有堆栈信息等,一旦setjump的被调用的函数返回则相应的环境会被释放,导致longjump无法在恢复到setjump调用位置,可能造成程序奔溃。声明:文章授权转自“最后一个bug”,版权归原作者所有。如有侵权,请联系我们删除!
❤「有用请分享」❤
????点击关注,技术干货准时送达!????