首页 | 博客群 | 公社 | 专栏 | 论坛 | 图片 | 资讯 | 注册 | 帮助 | 博客联播 | 随机访问
相等性判断的自动化- -| 回首页 | 2005年索引 | - -上帝是存在的

为goto正名

                                      

昨天和老板一块儿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语句就背负了它不该承受的恶名。到了为其平反的时候了。

【作者: 上帝没发笑】【访问统计:】【2005年01月31日 星期一 04:34】【注册】【打印

Trackback

你可以使用这个链接引用该篇文章 http://publishblog.blogchina.com/blog/tb.b?diaryID=650141

回复

- 评论人:习惯   2007-02-01 16:06:01   

goto 效果奇好,小范围内可以用一用:)

- 评论人:斯科蒂   2007-02-01 16:05:20   

goto 效果奇好,小范围内可以用一用:)

- 评论人:斯科蒂   2007-02-01 16:05:18   

goto 效果奇好,小范围内可以用一用:)

- 评论人:上帝没发笑   2005-03-09 13:39:53   

代码的可读性的好坏,不在于是否使用goto。不用goto语句的代码仍然可能是晦涩难懂的天书;使用了goto你的代码仍然会非常高效清晰。

所以,正像我文中所谈到的,我们应该把我们的目标定义在:“如何编写可读性良好的程序”。如果goto在某些情况下可以帮我们做到这一点,使用它!如果goto让我们代码混乱,别用它!同样,我们可以把这个观点用在其它机制上,如果if或while在某些情况下让我们的代码更清晰,使用它!否则,别用它!

你的例子正好说明了这一点,我们最好不要写嵌套太深的循环,这其中已经不是goto的问题了,而是过深的嵌套会让代码难以阅读(无论是否有goto),我们不会因此就反对使用while吧?

这其中的道理,正像小平同志的“黑猫白猫”理论那样,我们为什么非要那么教条呢?

"goto"与否,其实并不重要,重要的是,你是否清楚你真正的目标。用不用goto都只不过是达到目标的一种手段或途径罢了。

- 评论人:爪子   2005-03-09 01:29:30   

虽然我是菜鸟,我仍然反对使用GOTO,至少在情非得己的情况下绝对不用,这并非受教条主义影响,面对业务进行编程的时候,有多大的几率出现楼主例子中如此简单的逻辑??
我觉得自己很少会去写一个N多重嵌套的循环.通常面对复杂业务,多重的循环嵌套会被拆分成几个函数,而每一个函数都分担一部分计算工作,并且可以将自己的运行状态通过返回值让调用者获取信息,这样的程序可以非常容易的被改写,而且绝对比goto语句更容易让人看懂(除非你喜欢用aaa,bbb的去命名函数)
很难想象在一个略大一点的工程中,要对业务逻辑进行修改或扩展时看到goto语句以及N重嵌套循环时,自己会是什么表情
还有我想说的是,程序员写的代码永远不是给自己看的,既然避免使用goto已经成为绝大多数程序员的习惯,楼主的坚持似乎很难让别人认同哦^_^

- 评论人:上帝没发笑   2005-02-02 15:40:01   

要知道对于现在的程序设计而言,goto已经不像早期的汇编语言,大段的跳来跳去,而是在一个函数的内部进行跳转。goto的影响范围也仅仅在使用了goto的函数内部,所以,我根本不知道goto语句和系统的大小之间有何关系?

要知道,一个正常函数的范围都是在100行以内,大多数函数都只有几行或十几行。

这些小程序段对于goto的使用,和在大系统中,无论你的系统有多大,对于goto的使用,对系统造成的影响和结果是一样的。

仅仅靠本能的直觉是得不到问题的真相的,不知君以为然否?

- 评论人:上帝也疯狂   2005-02-02 13:35:50   

这么小段程序是体现不出来goto的好处和坏处的。不过现在的程序goto少多了倒是。

- 评论人:上帝没发笑   2005-02-02 11:30:43   

Linux算是大项目吧,你看看Linux内核中有多少goto,但Linux却是迄今为止最成功的Open Source Software。

即使是反对goto的人也是说不要滥用goto,而不是不用。要知道对于任何元素的滥用,都会导致负面的结果,而不仅仅是goto。正所谓“过犹不及”

真正的高手不会受限于那些针对初学者的清规戒律。

- 评论人:匿名网友   2005-02-02 10:23:16   

孩子你还小,我们原谅你了
在一个大项目中,存在 goto 简直就是灾难

- 评论人:Alex   2005-01-31 13:44:25   

理应如此。

验证码:   
评论内容: