龙空技术网

C语言中比goto还要"霸道"的跳转方式

嵌入式小美老师 165

前言:

目前朋友们对“c语言中不可以嵌套的是”都比较关切,你们都需要学习一些“c语言中不可以嵌套的是”的相关资讯。那么小编也在网络上网罗了一些有关“c语言中不可以嵌套的是””的相关资讯,希望大家能喜欢,看官们一起来了解一下吧!

相信当你看到这个标题,可能隐隐约约知道今天要谈的话题了。

没错,今天跟大家介绍一种比goto还要任性的跳转方式,即C函数库中的如下两个函数:

1//所需头文件2#include <setjmp.h>34int 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的第二个非零参数。

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!

无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。

点击这里找小助理0元领取:嵌入式物联网学习资料(头条)

2

跟goto有啥区别?

以前我也跟大家介绍过goto这匹野马被驯服的方式(goto关键字你不知道的"那些事"(C语言提升)),在C语言中goto只能实现函数内部的跳转,无法实现跨函数的直接跳转,比如函数嵌套多层的跳转等等。

当然你也可以借助goto与函数返回配合完成函数之间的跳转,不过那太麻烦了,所以这两个库函数该派上用场了。

这样的跳转太过于霸道,我们还是限制一下,切不可滥用,但其为异常处理代码的模块化带来了福音,在非常多的开源库中都有实际应用。

下面给大家一个参考示例 :

 1#include <stdio.h> 2#include <setjmp.h> 3 4jmp_buf mark; 5int  fperr; 6void fpcheck(void); 7 8/********************************************* 9 * Function: main10 * Description : 主任务函数11 * Note:(公众号:最后一个bug)12 *********************************************/13int  main( void )14{15    int jmpret;1617    //记录异常代码与正常代码分支位置18    jmpret = setjmp(mark);19    if( jmpret == 0 )20    {21        //正常用户程序运行2223    }24    else25    {26        //在正常用户程序运行过程中发生异常27        fpcheck();  28    }29}30/*********************************************31 * Function: Errorhandler32 * Description : 异常中断,在正常用户程序运行过程中发生异常处理函数33 * Note:(公众号:最后一个bug)34 *********************************************/35void Errorhandler(void)36{37    fperr = num;38    longjmp( mark, -1 ); //进行长跳转到异常处理39}4041/*********************************************42 * Function: fpcheck43 * Description : 故障处理函数44 * Note:(公众号:最后一个bug)45 *********************************************/46void fpcheck(void)47{4849    switch( fperr )50    {51        case INVALID:52            //user Code 53            break;5455        case OVERFLOW:56            //user Code 57            break;5859        case ZERODIVIDE:60            //user Code 61            break;62        default:63            break;64    }6566}

3

局限性

这组函数除了前面介绍的注意事项,还有一个非常值得注意的点就是longjump的调用时机必须在setjump被调用的所在函数返回前。

因为setjump保存有堆栈信息等,一旦setjump的被调用的函数返回则相应的环境会被释放,导致longjump无法在恢复到setjump调用位置,可能造成程序崩溃。

转载自:最后一个bug

文章来源于C语言中比goto还要"霸道"的跳转方式

原文链接:

标签: #c语言中不可以嵌套的是