为什么Linux内核里大量使用goto,而很多书籍却不提倡使用?

关于C语言的goto语句存在很多争议,很多书籍都建议“谨慎使用,或者根本不用”。Linux之父Linus在Linux中大量使用goto,也是在启示着我们可以合理使用goto语句。

存在即合理,既然是C语言中的一个知识点,我们还是有必要学会使用。先看一些goto如何用:

一、goto的基本语法

goto语句有两部分:goto和标签名。标签的命名规则与变量的命名规则一样。如:

goto label;

要让这条语句正常工作,函数还必须包含另一条标为label的语句,该语句以标签名后紧跟一个冒号开始,如:

label:printf("goto here.\n");

二、goto的例子

左右滑动查看全部代码>>>

/*
编译环境:mingw32 gcc6.3.0
*/
#include <stdio.h>
#include <stdlib.h>

/* goto测试 */
void TestGoto(void)
{
    int i;

while (1)
    {
for (i = 0; i < 10; i++)
{
    if (i > 6)
    {
goto label;
    }
    printf("%s : i = %d\n", __FUNCTION__, i);
}
    }
label:
    printf("test goto end!");
}

int main(void)
{
TestGoto();
}

运行结果:

从运行结果我们明显可以知道goto用法,可以跳出多重循环,程序执行过程中遇到goto语句就可以跳转到label处继续执行。

值得注意的一点是:goto语句与其跳转的标签处必须在同一个函数内。

三、goto与break、continue的区别?

同样是跳转语句,goto语句与break、continue语句有什么区别呢?

实际上,break和continue是goto的特殊形式。使用break与continue的好处是:其名称已经表明他们的用法。

下面通过代码实例看一下break与continue的用法:

1、break测试函数

使用上面的测试程序,建一个测试break语句的函数void TestBreak(void);,如:

左右滑动查看全部代码>>>

/* break测试 */
void TestBreak(void)
{
    int i;

while (1)
    {
for (i = 0; i < 10; i++)
{
    if (i > 6)
    {
        break;/* 第一个break:跳出for循环 */
    }
    printf("%s : i = %d\n", __FUNCTION__, i);
}
printf("Now i = %d\n", i);
break; /* 第一个break:跳出while循环 */
    }
    printf("test break end!");
}

运行结果:

从运行结果我们明显可以知道,break可以退出当前循环。

在本例子中,第一个break语句退出当前的for循环,第二个break语句退出当前的while循环。可见,一个break可退出一层循环。

所以,根据break与goto的特点知道,如果是跳出很多层循环,使用goto会方便些。

2、continue测试函数

同样的,建一个测试continue语句的函数void TestContinue(void);,如:

左右滑动查看全部代码>>>

/* continue测试 */
void TestContinue(void)
{
    int i;

for (i = 0; i < 10; i++)
    {
if (i > 6)
{
    printf("i = %d, continue next loop\n", i);
    continue;/* continue:结束本次循环(而不是终止这一层循环)继续进入下一次循环 */
}
printf("%s : i = %d\n", __FUNCTION__, i);
    }
    printf("test break end!");
}

运行结果:

从运行结果我们明显可以知道,continue可以结束本次循环(而不是整个循环)而进入下一次循环(i所代表的就是循环的次数)。

四、支持与反对goto的理由是什么?

1、不提倡使用goto

不提倡使用goto的占比应该比较多,不提倡的原因主要是:很容易把逻辑弄乱且难以理解。

2、使用goto的理由

这一部分人认为goto可以用在以下两种情况比较方便:

(1)跳出多层循环。

这个例子就类似于我们上面的goto测试程序。

(2)异常处理。

一个函数的执行过程可能会产生很多种情况异常情况。下面有几种处理方式,以代码为例:

方法一:做出判断后,如果条件出错,直接return。

左右滑动查看全部代码>>>

int mystrlen(char *str)
{
int count = 0;
if (str == NULL)
{
return -1;
}

if (*str == 0)
{
return 0;
}

while(*str != 0 )
{
count++;
str++;
}
return count;
}

方法二:先设置一个变量,对变量赋值,只有一个return。

左右滑动查看全部代码>>>

int mystrlen(char *str)
{
int ret;
if (str == NULL)
{
ret = -1;
}
else if (*str == 0)
{
ret = 0;
}
else
{
ret = 0;
while(*str != 0 )
{
ret++;
str++;
}
}
return ret;
}

方法三:使用goto语句。

左右滑动查看全部代码>>>

int mystrlen(char *str)
{
int ret;
if (str == NULL)
{
ret = -1;
goto _RET;
}

if (*str == 0)
{
ret = 0;
goto _RET;
}

while(*str !=0 )
{
ret++;
str++;
}

_RET:
return ret;
}

其中,方法三就是很多人都提倡的方式。统一用goto err跳转是最方便且效率最高的,从反汇编语句条数可以看出指令用的最少,消耗的寄存器也最少,效率无疑是最高的。

并且,使用goto可以使程序变得更加可扩展。当程序需要在错误处理时释放资源时,统一到goto处理最方便。这也是为什么很多大型项目,开源项目,包括Linux,都会大量的出现goto来处理错误!

以上就是关于goto语句的基本使用、goto与break、continue的区别的总结,如有错误,欢迎指出!如果觉得不错可以帮忙分享~

参考资料:

1、《C Primer Plus》
2、https://www.cnblogs.com/trying/archive/2012/06/25/2863753.html

猜你喜欢:

【socket应用】基于C语言的天气客户端的实现

【socket笔记】TCP、UDP通信总结

【C语言笔记】联合体怎么用?

【C语言笔记】关于数组的一个陷阱!

《注重这些细节可以提高我们的编程水平

《局部变量、 全局变量、 堆栈、 静态和全局

【Linux笔记】文件的权限

【Linux笔记】Vi/Vim编辑器

《省电子设计竞赛一等奖作品分享(三)

我的个人博客:

https://zhengnianli.github.io

查看往期笔记:

聊天界面输入m获取往期笔记目录

(0)

相关推荐

  • 零基础学C语言循环与控制结构

    https://m.toutiao.com/is/eLASn2y/ 这是一个C语言系列文章,如果是初学者的话,建议先行阅读之前的文章.笔者也会按照章节顺序发布. 本篇详细讲解循环结构与控制结构.对于每 ...

  • Linux之父将爱刻进Linux内核代码里

    Linux Kernel 官方网站 我们来看一段有意思的Linux内核代码,这段代码在Linux系统重启代码reboot.h中,学过C语言的都知道文件名后缀为.h的文件主要是对函数的声明和一些变量的定 ...

  • 吐血整理的万字Linux内核源码规范

    从编码风格错误开始 快速修改编码风格的工具 scripts/checkpatch.pl scripts/Lindent astyle Linux 内核代码风格 1 缩进 2 把长的行和字符串打散 3 ...

  • Linux 内核 vs Windows 内核

    设为"星标",重磅干货,第一时间送达 来自公众号:小林coding Windows 和 Linux 可以说是我们比较常见的两款操作系统的. Windows 基本占领了电脑时代的市场 ...

  • 培训手记(一):徜徉在汉字的内核里

    我从来没想到,普普通通的汉字,竟然能够被王鹏伟老师讲得如此妙趣横生,令与汉字打交道多年的语文教师们听得如醉如痴. 王鹏伟老师是"东北派语文"的典型代表,因其学养深厚,在语文教学上造 ...

  • 为了写论文给 Linux “投毒”, Linux 内核维护者封杀明尼苏达大学

    整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 写过论文的人都知道,论文内容必须要有可靠的事实依据,或通过查阅书籍,或通过反复试验,总之不可能凭空捏造. 那么大家看看下面这篇论文的标题 ...

  • 深入理解Linux内核之内核抢占

    深入理解Linux内核之内核抢占

  • Linux内核中断顶半部和底半部的理解

    文章目录 中断上半部.下半部的概念 实现中断下半部的三种方法 软中断 软中断模版 tasklet tasklet函数模版 工作队列 工作队列函数模版 进程上下文和中断上下文 软中断和硬中断的区别 硬中 ...

  • (1条消息) linux内核的内存分配函数

    作用 函数 devm_kzalloc() 和kzalloc()一样都是内核内存分配函数,但是devm_kzalloc()是跟设备(device)有关的, 当设备(device)被detached或者驱 ...

  • Linux内核TCP参数梳理

    关于TCP连接的过程就不再赘述了,直接看下图. 我们从一次tcp的传输开始分析,从建立连接.数据传输和断开连接三部分. 建立连接阶段 net.ipv4.tcp_syn_retries syn重传次数, ...