Linux c/c++编程--知识点(2)为什么Linux内核里大量使用goto

文章原文:https://blog.csdn.net/zhengnianli/article/details/106684280

返回知识列表:


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

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

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

一、goto的基本语法

goto 语句允许把控制无条件转移到同一函数内的被标记的语句。也就是说只能在函数内跳,只能在函数栈里面跳。
goto语句有两部分:goto和标签名。标签的命名规则与变量的命名规则一样。什么规则呢?就是不能有数字开头,不能是关键字!如:

goto label;

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

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

疑问一,可以是空语句吗?

lable:   ;  //这里是一个空语句。什么也不做,就是让程序从这里继续往后走。

OK,没问题。是可以的。

疑问二:可以有多个标签吗?

label1: printf("hello world1");

label2: printf("hello world2");

label3: printf("hello world3");

这个是肯定的。可以定义多个标签。那如何执行呢?当goto lable1之后,程序将继续

label 就等于一个地址名字,可以用于调到程序执行的地址。仅此而已,不会影响程序的运行。就好比,你调试的时候,设置的断点,有点像,呵呵。

有没有这种连续定义label的情况吗?是有的,见如下例子:

fail_map:
    close(bs->fd);

fail_open:
    free(bs);
    return 0;

以上这段,摘自 binder.c 中 binder_open 函数。

二、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的理由是什么?

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来处理错误。摘自《LINUX设备驱动程序》P38.

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值