为goto正名

转载 2007年09月22日 00:02:00

昨天和老板一块儿review我的code,当看到我的代码中存在一些goto语句的时候,老板条件反射般严肃的问我:“为什么要用goto语句”?

我很理解她为什么会惊讶。自从计算机科学一代宗师Dijkstra于1968年发表了著名的文章《Go To Statement Considered Harmful》之后,goto语句就成了过街老鼠,人人喊打。甚至有人开玩笑说:“今天你敢用goto,明天老板就让你go home”。

“不要在程序中使用goto”已经成为绝大多数开发者的圣经,但却很少有人认真的思考过,为什么会这样?

goto问题之所以这么臭名昭著,从历史的角度来看,在Dijkstra在ACM发表那篇文章之前,现代软件构造方法还没有出现,goto语句是当时实现流程控制的主要手段。那篇文章发表之后,引发了大量的争论,并最终导致了当代程序员认为理所当然的结构化编程的出现与风靡。

但有趣的地方也正在与此,结构化编程是由goto问题的争论产生的。从时间的顺序上讲,结构化编程语言Pascal,C及现代面向对象语言C++,Java,C#均出现在1968年之后,但为什么这些语言都保留了goto或与goto功能相近的语句?

所以,问题本身并不在于goto。Dijkstra之所以竭力反对goto的原因是因为泛滥的使用goto将会导致软件难以理解和跟踪。所以,我们要反对的是“难以理解和跟踪”的程序,而不是goto语句。

goto语句一定会造成程序“难以理解和跟踪”吗?不!恰恰相反,在适当的地方适当的使用goto恰恰可以让程序更加容易的理解和跟踪,甚至让代码更有效率。举个例子:

while(1) {
   ...
   do {
      ...
      for(i=0; i < max; i++) {
         if(a[i] == 10)
            goto done; 
         else
            count += a[i];
      }
      ...
   } while( n > 0);
   ...
}

done:
...

由于break只能跳出一级循环,在很深的循环嵌套中,如果存在一个从结束所有循环的需求,则goto是最能直接体现此意图,并让程序更简捷的手段。否则上面的代码不得不写为:

boolean finished = false;
while(1) {
   ...
   do {
      ...
      for(int i=0; i < max; i++) {
         if(a[i] == 10) {
            finished = true;
            break;
         }
         else
            count += a[i];
      }
      if(finished)
         break;
      ... 
   } while( n > 0);
  
   if(finished)
      break;
   ...
}

再看另外一个例子:

#define FREE(p) if(p) { /
     free(p); /
     p = NULL; /
   }
void foo()
{
   char *fname=NULL, *lname=NULL, *mname=NULL;
   fname = ( char* ) calloc ( 20, sizeof(char) );
   if ( fname == NULL ){
      goto ErrHandle;
   }
  
   lname = ( char* ) calloc ( 20, sizeof(char) );
   if ( lname == NULL ){
      goto ErrHandle;
   }
  
   mname = ( char* ) calloc ( 20, sizeof(char) );
   if ( mname == NULL ){
      goto ErrHandle;
   }

   ......

ErrHandle:
   FREE(fname);
   FREE(lname);
   FREE(mname);
   ReportError(ERR_NO_MEMOEY);
}

在这种情况下,goto语句会让你的程序更易读,更容易维护。

还有其它良好使用goto的例子,这里就不一一列举了。

孔子曰:“过犹不及”。教条主义般的反对goto,其原因和结果都只能是本末倒置。我们的核心思想是:构造易于阅读和理解的代码。只要抓住这一点,我们就能以平常心看待goto。不使用goto,仍然可以写出非常糟糕的代码;而使用了goto语句的程序,却很有可能是优秀的代码。事实上,goto和其它语句及机制一样,都只不过是为我们这个核心思想服务的手段或工具罢了。

自从1968年,goto语句就背负了它不该承受的恶名。到了为其平反的时候了。

 

为兔子正名!

一个人管理三个blog真是不容易啊,看来当年那个兔子也不是那么容易当的,还被人骂,留下“狡兔三窟”的臭名。起初我是想申请一个.com或.net的域名的,但是你要知道那个是要交钱的,而且价格不菲(对于我...
  • rainbow0229
  • rainbow0229
  • 2005年08月07日 21:15
  • 703

为“存在即是合理”正名

  为“存在即是合理”正名书上说:“存在即是合理”是唯心主义观。记得在电影中,主人公“佛罗德”看着丑陋的“咕噜”一直在暗中跟着远征队的时候,说咕噜不应该存活于这个世界上。这时“甘道夫”说了这么一句话:...
  • liumangxiong
  • liumangxiong
  • 2007年05月04日 20:54
  • 1440

为“自由软件”正名

软件是一种好东西,人人喜欢(必须)使用它。但是,在这个世界上原本没有可供“自由使用”的软件。在二十几年前,美国Richard Stallman提出一个设想,(自己动手)编写一些软件,让别人去“自由使用...
  • yuanmeng001
  • yuanmeng001
  • 2007年07月01日 18:51
  • 1166

为搜索引擎优化正名

国务院信息化工作办公室发布的《互联网络信息资源数量调查报告》显示,有51.5%的企业网站每天页面访问量在50次以下,这个比例还在不断扩大。面对1.62亿的网民群体,越来越多的中小企业意识到网络营销的重...
  • tmxsl1214
  • tmxsl1214
  • 2007年08月25日 21:05
  • 211

为Linux正名!

我已经半年没有使用 Windows 的方式工作了。Linux 高效的完成了我所有的工作。 GNU/Linux 不是每个人都想用的。如果你只需要处理一般的事务,打游戏,那么你不需要了解下面这些了。我不是...
  • yuanqingfei
  • yuanqingfei
  • 2004年07月05日 15:03
  • 2057

为PPT架构师正名

背景周末参加topgeek组织的2016年度中国架构师大会,日程之一是圆桌会议:“如何成为顶级架构师”。有意思的是,四位嘉宾一致和不写代码的“PPT架构师”撇清了关系,均表示至今还在撸代码。不出意外,...
  • u014652595
  • u014652595
  • 2016年05月03日 17:48
  • 197

GOTO语句利弊

一看就知道是goto和call分不清的孩子 然后在群里敲代码的时候,小猫用了Do...Loop循环,结果群里有个小朋友问Do...Loop循环是什么?-_-|||结果一群人都说很少用Do...Loo...
  • muzilanlan
  • muzilanlan
  • 2015年03月27日 10:35
  • 4528

Objective-C学习笔记(八)——高级跳转语句goto使用方法

在我们学习C语言的时候,碰到一种程序跳转,叫做goto,goto可以跳到程序的任意地方。又到了后来,学习了程序设计方法学,不知哪一位计算机前辈(貌似是迪杰斯特拉),认为goto使得程序的跳转过于随意,...
  • CHENYUFENG1991
  • CHENYUFENG1991
  • 2015年07月23日 10:09
  • 6016

C语言中使用goto语句

关于C语言是否该使用goto语句这里不再辩论。只讲讲goto语句的用法。 不建议使用goto语句,但是遇到goto语句我们要知道是什么 意思。 goto语句又叫无条件转移语句。 先看一个例子: v...
  • baidu_36649389
  • baidu_36649389
  • 2017年01月17日 14:20
  • 14859

SQL Server 流程控制中的 Goto 语句

--============================================================= -- 1, Goto语句 -- Desc:Goto语句可以让程序跳转...
  • ht_gaogao
  • ht_gaogao
  • 2014年02月26日 13:44
  • 1882
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:为goto正名
举报原因:
原因补充:

(最多只允许输入30个字)