C++ goto语句的理解与应用

以下来自新浪博客的转载:

1:为何不提倡使用goto语句?

渊源(来自wikipedia):

GOTO是一条可以在许多计算机编程语言中找到的语句。它是英文单词goto的组合。当执行这条语句的时候,它将控制流程无条件地转到另一条语句(也叫"跳转")。跳转语句需要指明标记,在不同语言中,标记可以是标识符或行号。在机器码级别,goto是一种分支的形式。

在一些语言中,可以不用显示地使用goto关键字而实现同样的功能,例如breakcontinue关键字可以跟随一个标识符。SNOBOL语言支持一种语句的后缀形式,可以在本条语句执行完毕后实现无条件跳转。

GOTO语句被大部分高级语言支持,只有很少的高级语言不支持GOTO语句。例如,goto是一个Java语言的保留字,但是不允许使用。例如Pascal中没有Goto,但可用procedure执行一外加语法。

GOTO语句一直是批评和争论的目标,主要的负面影响是使用GOTO语句使程序的可读性变差,甚至成为不可维护的“面条代码”。随着结构化编程在二十世纪六十年代到七十年代变得越来越流行,许多计算机科学家得出结论,即程序应当总是使用被称为“结构化”控制流程的命令,如循环以及if-then-else语句来替代GOTO。甚至在今天,许多程序风格编码标准禁止使用GOTO语句。为GOTO语句辩护的人认为,加以限制地使用GOTO语句不会导致低质量的代码,并且声称在许多编程语言中,一些任务如果不使用一条或多条GOTO语句是无法被直接实现的。如有限状态自动机的实现、跳出嵌套循环以及异常处理

大概最著名的对于GOTO的批评是艾兹格·迪杰斯特拉(Edsger Wybe Dijkstra)在1968年的一篇名称为《GOTO陈述有害论(英语:Go To Statement Considered Harmful)》的论文。[2]迪杰斯特拉认为不加限制地使用GOTO语句应当从高级语言中废止,因为它使分析和验证程序正确性(特别是涉及循环)的任务变得复杂。另外一种观点高德纳Structured Programming with go to Statements [3]中,文章分析了许多常见编程任务,然后发现其中的一些使用GOTO将得到最理想的结构。

这些批评在一些编程语言的设计上起到了效果。虽然Ada语言的设计者在二十世纪七十年代晚期意识到了对于GOTO的批评,这条语句仍旧被包含进去,主要是用来支持自动生成那些goto语句必不可少的代码。[4]但是,作为goto语句目的地的标签必须使用双尖括号括起来(如:<<Start_Again>>),而这个语法在其他语言中都不被使用。这使得检查程序中goto目的地的存在变得容易。goto语句本身使用简单的形式goto Start_Again;.


原因:  GOTO语句使程序的静态结构和动态结构不一致,从而使程序难以理解,难以查错。
有人认为GOTO语句使用起来比较灵活,而且有些情形能提高程序的效率。
1974年,D·E·克努斯对于GOTO语句争论作了全面公正的评述,其基本观点是:不加限制地使用GOTO语句,特别是使用往回跳的GOTO语句,会使程序结构难于理解,在这种情形,应尽量避免使用GOTO语句。但在另外一些情况下,为了提高程序的效率,同时又不至于破坏程序的良好结构,有控制地使用一些GOTO语句也是必要的。用他的话来说就是:“在有些情形,我主张删掉GOTO语句;在另外一些情形,则主张引进GOTO语句。”
后来,G·加科皮尼和C·波姆从理论上证明了:任何程序都可以用顺序、分支和重复结构表示出来。这个结论表明,从高级程序语言中去掉GOTO语句并不影响高级程序语言的编程能力,而且编写的程序的结构更加清晰。
goto语句的结果:在C/C++等高级编程语言中保留了goto语句,但被建议不用或少用。在一些更新的高级编程语言,如Java不提供goto语句,它虽然指定goto作为关键字,但不支持它的使 用,使程序简洁易读;尽管如此后来的c#还是支持goto语句的,goto语句一个好处就是可以保证程序存在唯一的出口,避免了过于庞大的if嵌套。
可以考虑使用goto的情形:1.从多重循环中直接跳出 ;2. 出错时清除资源; 3.可增加程序的清晰度的情况。
不加限制地使用goto:破坏了清晰的程序结构,使程序的可读性变差,甚至成为不可维护的"面条代码"。经常带来错误或隐患,比如它可能跳过了某些对象的构造、变量的初始化、重要的计算等语句。
goto语句问题的提出直接推动了结构化程序设计(structured programming)的思想和程序设计方法学的诞生和发展。结构化程序设计方法引入了工程思想和结构化思想,使大型软件的开发和编程都得到了极大的改善。结构化程序设计方法的主要原则可以概括为自顶向下,逐步求精,模块化,限制使用goto语句。
下列关于使用goto语句的原则可以供读者参考。   1) 使用goto语句只能goto到同一函数内,而不能从一个函数里goto到另外一个函数里。   2) 使用goto语句在同一函数内进行goto时,goto的起点应是函数内一段小功能的结束处,goto的目的label处应是函数内另外一段小功能的开始处。   3) 不能从一段复杂的执行状态中的位置goto到另外一个位置,比如,从多重嵌套的循环判断中跳出去就是不允许的。   4)应该避免像两个方向跳转。这样最容易导致"面条代码"。

 2:网友热心回答

goto并不是不能用,关键是goto指向的标签必须在goto这行的后面。
盲目禁用goto是不对的。
见杰拉尔德·温伯格《理解专业程序员》

如果要做软件开发的话,特别是团队的话,为了将来项目的维护和让代码通俗易懂,最好不要用goto;
goto会影响编译器优化,还有九成的goto都可以转换成不用goto的方式

如果GOTO的语句在后面就不会出现死循环!
如果GOTO的语句在前面就很容易死循环!!!
还有,GOTO  的语句都能用REPEAT或WHILE来代替!
所以,一般不用GOTO!!

因为那会扰乱编程结构次序

3:

正面:

goto语句在C/C++语言中可谓是“臭名昭著”,乃至有的书(或公司的编程规范)提出禁用goto语句的说法。其结果就是,造成有的程序员一看到goto语句在某程序中被使用,就本能地认为这个程序写得很“垃圾”。此外,也使得有些程序员因为使用了goto语句而觉得自己很不专业。其实,凡事都不能太偏激,goto语句运用得好能大大地简化程序,以及提高程序的可读性和可维护性。在开始示例其好处之前,先用一些统计数据来说明goto语句并没有因为“臭名昭著”而被抛弃,这些统计数据可能并不是百分之百的精确,但很具有说服力。对于操作系统,Linux-2.6.21内核使用了20,333个goto语句,VxWorks-6.2则使用了9142个,最后941个goto语句被运用到了rtems-4.9.2中;另外,glibc-2.9库使用了1750个goto语句。所有这些统计数据都表明,goto语言并没有想象的那样可怕而招到禁用,其关键在于 —— 恰当地运用它。

转载来自:http://blog.sina.com.cn/s/blog_6908039c0101f5hx.html

 

以下来自csdn博客的转载:

goto只能在函数体内跳转,不能跳到函数体外的函数。即goto有局部作用域,需要在同一个栈内。

需要在要跳转到的程序段起始点加上标号。如下例中的part2。

1.goto 语句可用于跳出深嵌套循环

  1. #include<iostream>   
  2. using namespace std;  
  3. int main()  
  4. {  
  5. for(int i=0;i<10;i++)  
  6.  for(int j=0;j<10;j++)  
  7.   for(int k=0;k<10;k++)  
  8.   {  
  9.          cout<<i*j*k<<" ";  
  10.          if(216==i*j*k)  
  11.             goto part2;//break是跳不出多重循环的    
  12.          }  
  13.          cout<<"此处被省略"<<endl;      
  14.   part2:  
  15.        cout<<"part2"<<endl;  
  16.   system("pause");  
  17. }  
#include<iostream>
using namespace std;
int main()
{
for(int i=0;i<10;i++)
 for(int j=0;j<10;j++)
  for(int k=0;k<10;k++)
  {
         cout<<i*j*k<<" ";
         if(216==i*j*k)
            goto part2;//break是跳不出多重循环的 
         }
         cout<<"此处被省略"<<endl;    
  part2:
       cout<<"part2"<<endl;
  system("pause");
}

2.goto语句可以往后跳,也可以往前跳

  1. #include<iostream>   
  2. using namespace std;  
  3.   
  4. int main()  
  5. {  
  6.     int x,sum=0;  
  7.     //定义标号L1   
  8. L1: cout<<"x=";  
  9.     cin>>x;  
  10.     if (x==-1)  
  11.        goto L2;          //当用户输入-1时,转到L2语句处   
  12.     else  
  13.        sum+=x;  
  14.     goto L1;             //只要用户没有输入-1,则转到L1语句处,程序一直将用户的输入默默地累加到变量sum中。   
  15.     //定义标号L2   
  16. L2: cout<<"sum="<<sum<<endl;//一旦转到L2,将输出累计结果,程序运行结束。   
  17.     system("pause");  
  18. }  
#include<iostream>
using namespace std;

int main()
{
    int x,sum=0;
    //定义标号L1
L1: cout<<"x=";
    cin>>x;
    if (x==-1)
       goto L2;          //当用户输入-1时,转到L2语句处
    else
       sum+=x;
    goto L1;             //只要用户没有输入-1,则转到L1语句处,程序一直将用户的输入默默地累加到变量sum中。
    //定义标号L2
L2: cout<<"sum="<<sum<<endl;//一旦转到L2,将输出累计结果,程序运行结束。
    system("pause");
}

3.也可以跳出switch,或者在case之间进行跳转

如:

  1. #include<iostream>   
  2. using namespace std;  
  3.   
  4. int main()  
  5. {  
  6. char a;  
  7. L1:  
  8. cout<<"请输入一个字符"<<endl;  
  9. cin>>a;  
  10. switch(a)  
  11. {  
  12.   case 'a':  
  13.        cout<<"case a"<<endl;  
  14.        goto L1;  
  15.        //break;   
  16.   L2:  
  17.   case 'b':  
  18.        cout<<"case b"<<endl;  
  19.        break;  
  20.   case 'c':  
  21.        cout<<"case c"<<endl;  
  22.     //   break;   
  23.        goto L2;  
  24.   default:  
  25.           break;  
  26. }  
  27.   system("pause");  
  28. }  
  29.     
#include<iostream>
using namespace std;

int main()
{
char a;
L1:
cout<<"请输入一个字符"<<endl;
cin>>a;
switch(a)
{
  case 'a':
       cout<<"case a"<<endl;
       goto L1;
       //break;
  L2:
  case 'b':
       cout<<"case b"<<endl;
       break;
  case 'c':
       cout<<"case c"<<endl;
    //   break;
       goto L2;
  default:
          break;
}
  system("pause");
}
  



转载来自: http://blog.csdn.net/generalhking/article/details/8011306
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值