你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

关键字goto在C语言中的使用

[复制链接]
gaosmile 发布时间:2020-6-24 09:55
1、goto关键字基础知识
关键字goto从字面的意思就是"去哪里"的意思,专业一点的话表示无条件跳转的意思(有学过汇编的小伙伴应该会觉得非常像jump指令),在C语言中的使用格式是:goto label,表示跳转到label的位置,并且我们的label一般都写在语句的开头,写成label:的形式。(下面一个小例子来简单介绍用法)
  • int main(int argc, char *argv[]) {
  •     //无条件跳转到标签处
  •     goto thelastBug;

  •     printf("未知bug\n");

  • //标签定义
  • thelastBug:  

  •     printf("最后一个bug\n");
  •     return 0;
  • }


注意点:
    1)goto label;后面的分号一定得打。(个人经常忘记,这里提醒一下各位)
    2)goto只能在函数内部无条件跳转,不能从一个函数跳转到另外一个函数。
    3)label:的标识在使用goto语句的前后均可,不遵循先定义后使用。
    4)label的作用域在函数内部,不同函数之间可以定义相同的label。
    (上面的几点注意项大家有时间可以在电脑上实验下)

2、备受争议的C语言关键字-goto
对于goto的使用程序语言界算是争议不断,并且大部分大学C语言老师在讲到到goto这关键字的时候一般都会叫大家慎用goto关键字,甚至有部分老师一棍子拍死“禁止使用goto关键字”。个人觉得一棍子打死终究不合适,慎用比较说得过去点。如果说禁止使用那为什么还要在C语言标准中定义呢?干脆直接剔除算了。有句话说得好,"存在即合理"。

我们在高中学习算法的时候应该画过基本的结构图,三大基本的程序结构分别是:顺序结构、分支结构和重复结构,这个三种结构就能够创造出所有的逻辑结构,那么我们C语言就是顺序执行的表示顺序结构;if、switch等表示分支结构;while、for等结构表示的是重复结构。可以说我们不用goto语句也能编写出我们想要实现的程序。

那么我们换一种思考方式,我们的重复结构就比如说三个循环语句for、while、do...while,在我的实践编程经验来看他们都可拆成:一个分支语句+goto语句,下面我举一个if+goto实现for语句的例子供大家参考:

  • /**********************************
  • * Fucion: main
  • * Descri: if+goto 模拟for语句
  • **********************************/
  • int main(int argc, char *argv[]) {
  •     //循环变量定义
  •     int i = 0;

  •     i = 0;
  • Loop:if(i > 5){goto  LoopEnd;}i++;
  • //for(i= 0;i<5;i++)
  • //{
  •     printf("%d\n",i);
  •     goto  Loop;
  • //}
  • LoopEnd:

  •     printf("最后一个bug\n");
  •     return 0;
  • }

   
其他的重复语句也可以由分支+goto模拟,这里就不再书写代码了,只是说用模拟循环的方式似乎书写上不是很美观。所以我觉得并不是goto不好用,而是怕大家滥用,导致对程序的把控力的下降。

那么我们再深入一点看待goto语句,我上面说了该关键字非常的灵活,其实goto本身的功能是非常简单的,就是一个跳转到所定义的标签label位置,灵活的地方在于label可以在一个函数内部每一句的开头都可以定义。

所以我们要控制goto为我们所用主要就是控制label的使用问题,后面我们会有例子教大家怎么控制label,所以goto语句还是一个非常有潜力的关键字,对于设计巧妙高效的算法会非常有用!所以个人觉得只要对goto语句的使用加以管束为我们开发服务,这未尝不是一件好事。


3、大佬都是这么用goto的!
1)瞄一瞄linux中的goto
我们读过linux相关代码的小伙伴会发现goto语句的使用无处不在,首先我截取了uboot1.1.6中的一部分代码来欣赏一下(毕竟uboot也是大佬写的):

微信图片_20200624095511.png

微信图片_20200624095515.png

第一张是一个函数的前半部分,第二张为该函数末尾,中间代码还有非常多这样的语句。程序大体的意思是:打开一个文件,然后对该文件一系列操作,一旦操作不成功就会goto到error标签,然后关掉该文件,否则如果都执行成功了就会return 1.表示成功。

没错,这是goto常用的一种用法就是处理多种异常情况,这样带来的好处是高效,为什么这么说呢?有些小伙伴就就会问题了,我直接在每个错误处理用return返回一个变量,然后再函数外面通过判断这个标志进行故障处理不就好了吗?

个人觉得如果你有这样的想法是好的,不过在我们进行驱动编程的过程中还是要有一定的规范,如上面的代码我们在函数前面申请了mem_fb,既然没有使用成功我们就应该在该函数中直接释放它,这样能够对函数有更好的封装和隐秘性。那有些小伙伴又会说,分支语句每个分支里面进行处理就好了呀,这种处理方式会使得每个分支语句里面都有相同的释放处理语句,加大了程序。

2)使用goto跳出多层循环
我们都知道break仅仅只能跳出当前循环,如果遇到多层循环需要跳出的问题,就需要每个循环都需要break一下,并且还需要内层循环传递相关信号让外层循环break掉,从而退出多层循环,这样做实在有点麻烦,而且代码结构也不好看,那么有些小伙伴就会问那我直接return掉就好了,我们来看一下下面的代码你就会有自己的决定了:

  • /**********************************
  • * Fucion: main
  • * Descri: goto跳出多层循环
  • **********************************/
  • int main(int argc, char *argv[]) {
  •     int i = 0,j = 0,k = 0;

  •     for(i = 0 ;i < 10;i++)
  •     {
  •         for(j = 0 ;j < 10;j++)
  •         {
  •             for(k = 0 ;k < 10;k++)
  •             {
  •                 //if(条件不满足)
  •                 //goto ERROR;
  •             }
  •             //if(条件不满足)
  •             //goto ERROR;
  •         }   
  •         //if(条件不满足)
  •         //goto ERROR;
  •     }
  •     return 1;
  • ERROR:
  •     //相关资源释放
  •     printf("最后一个bug\n");
  •     return 0;
  • }

  • /**********************************
  • * Fucion: main
  • * Descri: return跳出多层循环
  • **********************************/
  • int main(int argc, char *argv[]) {
  •     int i = 0,j = 0,k = 0;

  •     for(i = 0 ;i < 10;i++)
  •     {
  •         for(j = 0 ;j < 10;j++)
  •         {
  •             for(k = 0 ;k < 10;k++)
  •             {
  •                 //if(条件不满足)
  •                 //相关资源释放
  •                 //return 0;
  •             }
  •             //if(条件不满足)
  •             //相关资源释放
  •             //return 0;
  •         }   
  •         //if(条件不满足)
  •         //相关资源释放
  •         //return 0;
  •     }
  •     printf("最后一个bug\n");
  •     return 1;
  • }


3)作者对goto关键字小结
这里仅仅代码个人的使用观点:

(1)上面两个例子中我们使用goto是可以借鉴的,对程序的效率和美观有一定的效果;

(2)对于一般的程序goto语句的功能尽量简单,便于分析和代码的整洁,如果不能带来较大的优势还是尽量少用;

(3)个人平时研究控制理论,对于任何事物觉得要么是发散、要么是收敛比较好分析处理问题,对于震荡问题相对比较麻烦,所以对于如下图2种goto的使用情景我是推荐的,前面说了只要我们控制好goto的灵活度就能够为我们服务,那么我们只需要规定在一个函数中其只是单向跳转,我们对程序的把控能力就大大提高了。

微信图片_20200624095519.png


4、总结
好了,今天的内容就到这里吧,看完这个文章希望大家能够有点收获吧,也希望大家能帮忙传播传播

收藏 评论0 发布时间:2020-6-24 09:55

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版