C语言中比goto还要"霸道"的跳转方式
来源:TopSemic嵌入式发布时间:2023-03-07843浏览
询问 AI相信当你看到这个标题,可能隐隐约约知道今天要谈的话题了。没错,今天跟大家介绍一种比goto还要任性的跳转方式,即C函数库中的如下两个函数:
一些朋友该说了,我从来不用这些跳转,免得出问题。还是一直以来的那句话,"存在即合理"~我们来看看这两个函数到底有什么可以推敲的东西。1//所需头文件
2#include<setjmp.h>
3
4intsetjump(jmp_bufbuf)
5voidlongjump(jmp_bufbuf,inti)
6
1
函数介绍
有研究过RTOS的朋友应该对此不难理解,setjump主要是保存当前函数调用点的现场环境(或者叫上下文),比如各种寄存器、堆栈等等,那么这些环境信息就记录在jmp_buf所定义的buf中。
而当我们在其他位置调用longjump函数就相当于一个长跳转,传入之前保存在buf中的信息,即可跳回到之前setjump所调用的位置(理解为恢复setjump所保存的环境也是可以的)。
所以这里值得注意的是不要率先调用longjump,否则程序不知道飞去哪里了。
其实跟RTOS中进行任务切换有着异曲同工之妙。
你大概已经注意到setjump有一个返回值,其主要分为两种情况:
当直接调用setjump函数,则返回0;
当调用longjump跳转到setjump位置,则其返回longjump的第二个非零参数。
2
跟goto有啥区别?
以前我也跟大家介绍过goto这匹野马被驯服的方式(goto关键字你不知道的"那些事"(C语言提升)),在C语言中goto只能实现函数内部的跳转,无法实现跨函数的直接跳转,比如函数嵌套多层的跳转等等。
当然你也可以借助goto与函数返回配合完成函数之间的跳转,不过那太麻烦了,所以这两个库函数该派上用场了。
这样的跳转太过于霸道,我们还是限制一下,切不可滥用,但其为异常处理代码的模块化带来了福音,在非常多的开源库中都有实际应用。
下面给大家一个参考示例 :
1#include<stdio.h>
2#include<setjmp.h>
3
4jmp_bufmark;
5intfperr;
6voidfpcheck(void);
7
8/*********************************************
9*Function:main
10*Description:主任务函数
11*Note:(公众号:最后一个bug)
12*********************************************/
13intmain(void)
14{
15intjmpret;
16
17//记录异常代码与正常代码分支位置
18jmpret=setjmp(mark);
19if(jmpret==0)
20{
21//正常用户程序运行
22
23}
24else
25{
26//在正常用户程序运行过程中发生异常
27fpcheck();
28}
29}
30/*********************************************
31*Function:Errorhandler
32*Description:异常中断,在正常用户程序运行过程中发生异常处理函数
33*Note:(公众号:最后一个bug)
34*********************************************/
35voidErrorhandler(void)
36{
37fperr=num;
38longjmp(mark,-1);//进行长跳转到异常处理
39}
40
41/*********************************************
42*Function:fpcheck
43*Description:故障处理函数
44*Note:(公众号:最后一个bug)
45*********************************************/
46voidfpcheck(void)
47{
48
49switch(fperr)
50{
51caseINVALID:
52//userCode
53break;
54
55caseOVERFLOW:
56//userCode
57break;
58
59caseZERODIVIDE:
60//userCode
61break;
62default:
63break;
64}
65
66}
3
局限性
这组函数除了前面介绍的注意事项,还有一个非常值得注意的点就是longjump的调用时机必须在setjump被调用的所在函数返回前。
因为setjump保存有堆栈信息等,一旦setjump的被调用的函数返回则相应的环境会被释放,导致longjump无法在恢复到setjump调用位置,可能造成程序崩溃。
最后
好了,今天先就跟大家分享这么多了,这一块还有一些东西可以挖掘,后面再整理一下分享出来,如果你觉得有所收获,一定记得点个赞~
扫码加入嵌入式交流群:

新闻来源:TopSemic嵌入式,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。

