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

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

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

  • & s$ \' V9 P% R' A
  •     printf("未知bug\n");
  • " }/ n# ^/ L6 {( `$ A
  • //标签定义
  • thelastBug:  
  • . ?4 q- |/ h' A! W' i1 o7 G, \
  •     printf("最后一个bug\n");
  •     return 0;
  • }

    1 T, D$ E" W5 B- r/ [: v2 I6 H

) k( u; R; R( F2 M( j" [
注意点:
    1)goto label;后面的分号一定得打。(个人经常忘记,这里提醒一下各位)
    2)goto只能在函数内部无条件跳转,不能从一个函数跳转到另外一个函数。8 c% b: Q4 z  c1 t
    3)label:的标识在使用goto语句的前后均可,不遵循先定义后使用。
. e8 K6 d. E/ E5 p
    4)label的作用域在函数内部,不同函数之间可以定义相同的label。
' G( ~6 H( P" O$ u/ o/ V
    (上面的几点注意项大家有时间可以在电脑上实验下)

  d+ x; p3 b3 P3 s/ |& d9 p" h- E0 e) ]. }
2、备受争议的C语言关键字-goto
对于goto的使用程序语言界算是争议不断,并且大部分大学C语言老师在讲到到goto这关键字的时候一般都会叫大家慎用goto关键字,甚至有部分老师一棍子拍死“禁止使用goto关键字”。个人觉得一棍子打死终究不合适,慎用比较说得过去点。如果说禁止使用那为什么还要在C语言标准中定义呢?干脆直接剔除算了。有句话说得好,"存在即合理"。
  Y5 K2 [& f  o2 }3 P+ [
我们在高中学习算法的时候应该画过基本的结构图,三大基本的程序结构分别是:顺序结构、分支结构和重复结构,这个三种结构就能够创造出所有的逻辑结构,那么我们C语言就是顺序执行的表示顺序结构;if、switch等表示分支结构;while、for等结构表示的是重复结构。可以说我们不用goto语句也能编写出我们想要实现的程序。* a5 t6 w& ~. D  ~" R: \! M

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

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

  • 8 K: N+ o5 F. z2 S, N6 d" B1 u
  •     i = 0;
  • Loop:if(i > 5){goto  LoopEnd;}i++;
  • //for(i= 0;i<5;i++)
  • //{
  •     printf("%d\n",i);
  •     goto  Loop;
  • //}
  • LoopEnd:
  • & I* |. |  A& m- c& W/ n8 x+ V
  •     printf("最后一个bug\n");
  •     return 0;
  • }

    : G- Z7 i: l. z4 V- J8 t! }
   
其他的重复语句也可以由分支+goto模拟,这里就不再书写代码了,只是说用模拟循环的方式似乎书写上不是很美观。所以我觉得并不是goto不好用,而是怕大家滥用,导致对程序的把控力的下降。
+ |. ]) p6 F4 S( u& h. {2 d" @
那么我们再深入一点看待goto语句,我上面说了该关键字非常的灵活,其实goto本身的功能是非常简单的,就是一个跳转到所定义的标签label位置,灵活的地方在于label可以在一个函数内部每一句的开头都可以定义。
  u2 D( w8 d% s- W. C1 t' U5 o+ T
所以我们要控制goto为我们所用主要就是控制label的使用问题,后面我们会有例子教大家怎么控制label,所以goto语句还是一个非常有潜力的关键字,对于设计巧妙高效的算法会非常有用!所以个人觉得只要对goto语句的使用加以管束为我们开发服务,这未尝不是一件好事。

" e, q) j3 o; j# F" X  k* D$ I

1 C/ _1 @5 g+ r& O' F; O$ Z
3、大佬都是这么用goto的!
1)瞄一瞄linux中的goto
我们读过linux相关代码的小伙伴会发现goto语句的使用无处不在,首先我截取了uboot1.1.6中的一部分代码来欣赏一下(毕竟uboot也是大佬写的):
% P; i7 W8 X- z. ]# T4 c) N9 H$ c
微信图片_20200624095511.png

: v# A* B* D; {  z- P- p/ j# k8 x
微信图片_20200624095515.png

* M+ ?6 B" v1 \5 t5 M
第一张是一个函数的前半部分,第二张为该函数末尾,中间代码还有非常多这样的语句。程序大体的意思是:打开一个文件,然后对该文件一系列操作,一旦操作不成功就会goto到error标签,然后关掉该文件,否则如果都执行成功了就会return 1.表示成功。
* d; x8 e1 ~" S* i( }! Z

7 \( L# H! C- T  \( m1 d
没错,这是goto常用的一种用法就是处理多种异常情况,这样带来的好处是高效,为什么这么说呢?有些小伙伴就就会问题了,我直接在每个错误处理用return返回一个变量,然后再函数外面通过判断这个标志进行故障处理不就好了吗?7 K: \# }5 G: A# L1 U7 v0 t' A

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

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

* H% }/ w4 L: ^( F
  • /**********************************
  • * Fucion: main
  • * Descri: goto跳出多层循环
  • **********************************/
  • int main(int argc, char *argv[]) {
  •     int i = 0,j = 0,k = 0;
  • % \! R7 g6 v, l
  •     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;
  • }
  • 8 s2 n' a3 Y5 |
  • /**********************************
  • * Fucion: main
  • * Descri: return跳出多层循环
  • **********************************/
  • int main(int argc, char *argv[]) {
  •     int i = 0,j = 0,k = 0;
  • ( z" Z) n  a. k/ d( v" @1 g
  •     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;
  • }

    8 W3 l* o5 N3 K

! v. J5 c- r) Y  Z- B5 V9 B1 ]
3)作者对goto关键字小结
这里仅仅代码个人的使用观点:
8 [; {9 }5 R! y
(1)上面两个例子中我们使用goto是可以借鉴的,对程序的效率和美观有一定的效果;' c$ e4 \8 F$ t, J0 I4 [# {3 F

' `  c# N3 b0 t# ]
(2)对于一般的程序goto语句的功能尽量简单,便于分析和代码的整洁,如果不能带来较大的优势还是尽量少用;( S3 C# U" s) l+ c% Z- G+ c
8 O/ n3 F. L/ ^2 \5 R8 X
(3)个人平时研究控制理论,对于任何事物觉得要么是发散、要么是收敛比较好分析处理问题,对于震荡问题相对比较麻烦,所以对于如下图2种goto的使用情景我是推荐的,前面说了只要我们控制好goto的灵活度就能够为我们服务,那么我们只需要规定在一个函数中其只是单向跳转,我们对程序的把控能力就大大提高了。

, _2 [8 U9 N- B% N
微信图片_20200624095519.png

$ D* y' f' z7 o: N

# D9 F" U& |: F; j& N: a, c& v% F
4、总结
好了,今天的内容就到这里吧,看完这个文章希望大家能够有点收获吧,也希望大家能帮忙传播传播
. i: U5 J- K$ X5 N! I
赞 收藏 评论0 发布时间:2020-6-24 09:55

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版