c语言goto语句用法_goto关键字你不知道的"那些事"(C语言提升)

894701546891ad21412ce88137eff49d.png

1、日常聊一聊(看文章与听音乐更配)

    今天在前面放了一段伍佰的歌曲《last Dance》,这首老歌最近突然火了是因为一部爱情穿越电视剧《想见你》,剧情还不错大家感兴趣可以看一看,大伙不要天天搞研究,敲代码,多一点不一样的生活会有不一样的精彩,效率也会大大提高。

    好了,之前一直都没有透露自己的联系方式,最近一些小伙伴私信给我说,有问题在公众号私信我比较麻烦而且有时候也没注意订阅号,希望我能够提供个人微信。确实最近发现私信的给我的图片有时候打不开,为了更好的交流这里公布一下个人的微信号,大家可以添加一下,研究、学习、生活上都可以跟我交流,我也可以准备酒,等待着你的故事:

f15ebf07287814013519e04622e522e3.png

    好了,要进入今天的主题了,今天我们要讨论的是C语言中相对比较冷门的知识关键字goto!

2、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。

    (上面的几点注意项大家有时间可以在电脑上实验下)

3、备受争议的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语句的使用加以管束为我们开发服务,这未尝不是一件好事。

4、大佬都是这么用goto的!

1)瞄一瞄linux中的goto 

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

3891ec41664d320d54af4492169d6a01.png

584a2449a0f78bf5e4880025b187caa1.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的灵活度就能够为我们服务,那么我们只需要规定在一个函数中其只是单向跳转,我们对程序的把控能力就大大提高了。

6af3992b3f13d882178e63f4c70acd54.png

5、总结

    好了,今天的内容就到这里吧,看完这个文章希望大家能够有点收获吧,也希望大家能帮忙传播传播,"再看"多点几个,大家的认可都是我坚持写作的动力源泉,写作这条路上还是需要大家多多陪伴。

    感谢关注公众号:"最后一个bug",我们下期见!

ffe4541d826fa396d0b540edc9017edd.png

推荐好文   点击蓝色字体即可跳转

☞一文教你定位单片机"死机"(实用调试技巧)99f034803481f3fe4e163cea822a0a3b.gif

☞嵌入式编程之"重构"代码(C语言版本) 99f034803481f3fe4e163cea822a0a3b.gif

☞单片机常用程序框架之分时轮询(详注代码) 99f034803481f3fe4e163cea822a0a3b.gif

☞【连载】通过"库文件"学单片机驱动编程(5)-完结篇99f034803481f3fe4e163cea822a0a3b.gif

☞【连载】嵌入式测试驱动开发(9) 99f034803481f3fe4e163cea822a0a3b.gif

☞手把手教你写Modbus-RTU协议(理论篇)99f034803481f3fe4e163cea822a0a3b.gif

☞嵌入式编程必备之多方法测定程序运行时间(经验篇)99f034803481f3fe4e163cea822a0a3b.gif

☞嵌入式编程之动态接口技术(经验干货)99f034803481f3fe4e163cea822a0a3b.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值