看到,网上很多人对于goto的询问, 因为本身在工作中经常使用到,所以写下此文, 如有错误, 请指出.

本人写博文的时候主要从事C++工作

对于goto的态度,本人目前成长如下:

学生时代

老师课堂上说,goto语句容易把程序的顺序逻辑结构扰乱. 由于是学生, 所以你懂的. 听老师的, 而且自己网上看了, 多数人也是反对使用goto的.备注:学生时代, 你也懂的, 根本没有考虑工程性. 很少使用goto, 也没有goto发挥的余地.

我的师傅

工作以后的,第一位师傅, 三星十年C语言图像算法工程师. 教育我说, 要学会在程序中使用goto. 不理解, 和她讨论了以前老师的一些想法.她当时举例大概如下:


#define FREE(p) {if(NULL!=(p){free(p);(p)=NULL;}} void fun()
{
int *p = NULL;
int *p1 = NULL;
int *p2 = NULL; p = (int *)malloc(sizeof(int) * 10);
if( NULL == p ){goto _END;}
p1 = (int *)malloc(sizeof(int) * 10);
if( NULL == p1 ){goto _END;}
p2 = (int *)malloc(sizeof(int) * 10);
if( NULL == p2 ){goto _END;} _END:
FREE(p);
FREE(p1);
FREE(p2);
}

当时,我也没有太理解. 目前理解了. 师傅是C语言,经常和内存打交道. 师傅当时的解释:对比上下代码


#define FREE(p) {if(NULL!=(p){free(p);(p)=NULL;}} void fun()
{
int *p = NULL;
int *p1 = NULL;
int *p2 = NULL; p = (int *)malloc(sizeof(int) * 10);
if( NULL == p )
{
return;
}
p1 = (int *)malloc(sizeof(int) * 10);
if( NULL == p1 )
{
FREE(p);
return;
}
p2 = (int *)malloc(sizeof(int) * 10);
if( NULL == p2 )
{
FREE(p);
FREE(p1);
return;
} /*...*/
}

也许你会认为这只是几个malloc, 你太天真了. 其实对于她们C开发, 有的时候, 函数体会很长, 而期间有一些函数会出错, 对于出错了, 怎么办? 使用goto, 来协定一个错误处理机制, 错误的处理, 也就是例子中内存的回收,统一放在函数的尾部, 不容易遗漏. 一旦某个地方出错了, 直接返回尾部即可.这是在调用malloc函数的时候, 其实, 自己写的函数, 也并不一定总是返回正确的结果. 那么如果函数一层一层嵌套的比较深了, 一个统一的错误处理机制是非常重要的, 尤其是在团队开发的时候. 目前,我所在的团队, 都是按照这个标准. 我们团队函数的基本模型如下:


int foo(int *p)
{
int nRet = -1; /** goto _END; */ if( 0 > foo1() ){goto _END;} nRet = 1;//只有当程序运行到底部,这里的时候, 这个函数才属于正常的运行完毕, 中间有任何的错误, 就会goto跳过这一步.
_END:
return nRet;
} //那么,我们来一次深层嵌套 int main()
{
int nRet = -1; if( 0 > foo() ){goto _END;} _END:
return nRet;
}

我这里仅仅采用了三层函数嵌套, 其实试想一下, 往往开发中, 我们会发现, 函数嵌套, 会在不知不觉中, 让我们都蛋疼的事情.

我的使用

师傅是C语言, 当时列举的例子是和内存相关的. 而我工作中主要是C++, 我们知道C++有new 和 delete, 这两个函数是相对于C的malloc 是比较安全. 由于目光短浅, 师傅的强制要求, 自己心里还有些不爽, 甚至和师傅进行了一次激烈的讨论. 因为我没有按照师傅的来. 师傅在检查我代码的时候, 批评了好几次. 拿自己的天真挑战师傅的经验. 肯定是失败的.

在慢慢的使用过程中, 我才体会到goto的强大魅力.有的时候,我们在程序中, 会有这样的逻辑.


int foo()
{
if( 条件1 )
{
if( 条件2 )
{
if( 条件3 )
{
/** ... */
}
}
else if( 条件4 )
{ }else
{
/**...*/
}
}
else if( 条件4 )
{
/**...*/
}
}

对于这样的程序逻辑, 你觉得可读性很强吗? 对于程序中的if else, 我是可笑又可恨, 我记得有些人甚至批判过if else, 能把你的思路绕晕了. if else的深层嵌套, 在goto这里, 可以优化成一层, 将其扁平化处理

int foo()
{
int nRet = -1; if( 条件1 )
{
/** do some thing */
goto _OK;
} if( 条件2 )
{
/** do some thing */
goto _FAILED
} if( 条件3 )
{
/** do some thing */
goto _OK;
} if( 条件4 )
{
/** do some thing */
goto _OK;
} _OK:
nRet = 1; _FAILED:
return nRet;
}

上下两部分不能完全对应, 我只是举个例子.也就是说, goto可以处理复杂的if else.

使用goto注意事项

上面两个goto例子, 一个是师傅经常使用的, 一个是我慢慢体会到的. 当然了,师傅在上.goto很灵活, 会用的人, 能把goto的威力发挥出来, 就想只有孙悟空才可以发挥金箍棒的威力一样. 使用过程中, 需注意如下:

  1. 细心的应该发现, 我们所使用的地方,都是在一个函数内部.也就是说, goto, 只在函数内部,** 千万千万千万别goto到其他函数内部. **
  2. 使用goto, 编译器有时候, 会报出变量定义问题. 在一个代码作用域中, 所有变量的声明定义必须在第一个goto的前面. 我们团队一般要求,统一函数头部. 注意作用域的理解.
int foo()
{
int nRet = -1; if( 条件1 )
{
/** do some thing */
goto _OK;
} int num;//报错, 应该移动到前面
if( 条件2 )
{
/** do some thing */
goto _FAILED
} if( 条件3 )
{
int num3;//不报错, 因为在{}这个作用域, 是在goto的前面
/** do some thing */
goto _OK;
} if( 条件4 )
{
/** do some thing */
goto _OK;
} _OK:
nRet = 1; _FAILED:
return nRet;

坚定使用goto

体会到了goto的魅力, 我还没有坚定我的信念,知道我碰到了一些远古级别的代码的时候, 我笑了, 他们也在使用goto.

自我评鉴goto

这个世界上, 总是存在这么一个现象, 有人说好, 必定有人说坏. 说好的人能列举一大堆好的例子, 不好的依然. 对于goto,我想说, 会用的, 把他用好, 不会用的. 可以使用自己认为好的方法. 方法有很多, 我们的目的只有一个, 写出安全的代码, 和清晰的程序逻辑. 只要能达到这个目标, 什么方法都可以.

goto使用总结

  1. 团队开发协定函数的错误反馈机制
  2. goto处理if else的多层嵌套, 将其扁平化处理.

How To Use Goto?的更多相关文章

  1. 因为没用过,所以没想过的--goto

    今天读了读 Rui Maciel 大神写的 mjson parser,mjson 解析器是一个使用 ISO C 实现的小型 JSON 解析器.嵌入式项目中使用到了该解析器,随即拿出来看看. 看到如下代 ...

  2. bat脚本参数 if goto choice for使用的学习笔记。

    写过几次bat脚本,但一直没有总结,最近找到一个网页介绍bat,总结得很好,转自 http://www.jb51.net/article/49627.htm: 本文只总结我不会的,全面的看原网页就可以 ...

  3. 用goto做异常处理

    http://www.cnblogs.com/trying/archive/2012/06/25/2863753.html 今天在CSDN上看到的关于错误返回值的讨论,感觉非常有趣. 从中可以看出被教 ...

  4. 尽量用goto代替尾递归

    void PrintList(List L) { if(L!=Null) { PrintElement(L->Element); PrintLisr(L->Next); } } 所谓尾递归 ...

  5. C++:为什么说 goto 没有用

    要了解一个功能有没有用,首先应该分析它能实现的所有功能. goto 可以实现的功能只有两种:一,向前面跳:二,向后面跳.这两种情况对应三种功能:一,重复执行也就是循环:二,跳过一段代码也就是条件判断: ...

  6. C语言的傻瓜式随笔(二):全局变量、预编译、goto

    函数的作用:可以实现代码的重用. 函数只需要定义1次,那么函数中的代码就可以随意的调用.       -某不知出处的基本概念 学而时习之,如有误笔,请指正 一.goto跳转语句 goto在C语言的作用 ...

  7. GOTO Berlin: Web API设计原则

    在邮件列表和讨论区中有很多与REST和Web API相关的讨论,下面仅是我个人对这些问题的一些见解,并没有绝对的真理,InnoQ的首席顾问Oliver Wolf在GOTO Berlin大会上开始自己的 ...

  8. 辗转相除法求最大公约数,非goto

    #include<iostream> using namespace std; //不推荐用goto,当然用它更快 //辗转相除法求两数的最大公约数 int gcd(long int a, ...

  9. C语言字符串匹配、goto语句、关机命令使用

    1.程序执行修改窗口字体颜色命令: 2.程序执行修改窗口标题命令: 3.程序执行关机倒计时命令: 4.根据提示输入团队名称JYHACK TEAM 根据提示输入团队网址:http://bbs.jyhac ...

随机推荐

  1. 根据oracle的主键列生成SQLserver的主键

    根据oracle的主键列生成MsSQLServer的主键列 select 'alter table  ' || cu.table_name ||'  add constraint  '||' PK_' ...

  2. 求50-100内的素数(java)

    实现代码: public class sushu { public static void main(String[] args) { for(int i=50 ; i<=100; i++){ ...

  3. 帝国CMS如何自动生成sitemap.xml网站地图文件

    登录网站的后台http://你的域名/e/admin/ 进入后台栏目 =>增加自定义页面 =>选择直接页面,页面名称为:网站地图,文件名修改为  ../../sitemap.xml 内容填 ...

  4. 【转】iOS学习之translucent属性

    原文地址:http://www.jianshu.com/p/930643270455 总所周知,苹果从iOS7开始采用扁平化的界面风格,颠覆了果粉们"迷恋"的拟物化风格.对于开发者 ...

  5. 读取web项目properties文件路径 解决tomcat服务器找不到properties路径问题

    1.需求:有时候我们产品经理给我们的需求是会不断变化的,例如数量是1000现在变成500,我们不可以去改代码吧,这样很麻烦,所以就可以改配置文件properties(这个数据库链接一样),当然也有js ...

  6. Web前端性能测试-性能测试知多少---深入分析前端站点的性能

    针对目前接手的web前端的性能,一时间不知道从什么地方入手,然后经过查找资料,发现其实还是蛮简单的. 前端性能测试对象: HTML.CSS.JS.AJAX等前端技术开发的Web页面 影响用户浏览网页速 ...

  7. PHP用户注册与登录【1】

    需求分析 主要功能分为 用户注册.用户登录.用户退出.用户中心 四个部分. 用户注册 用户注册主要功能有: 注册信息表单填写界面 javascript 脚本初步检测用户输入的注册信息. 注册处理模块检 ...

  8. Markdown 语法总结

    Markdown 语法总结 Markdown是一个神奇的语言,他比html简单,它巧妙地将内容和格式结合起来.很多平台支持Markdown语法编辑,比如github.博客园等. 下面总结一Markdo ...

  9. html5 炫酷的字幕雨

    <!DOCTYPE html> <html> <head> <script src="http://tj.gamee456.com/jquery.1 ...

  10. 谢欣伦 - 原创软件 - 游戏专题 - 我的桌面My Desktop

    今天在网上看到一个用桌面背景当做拼图内容的游戏很新颖,反正今天下雨我也闲着,索性用了半天时间做了一个类似的游戏<MyDesktop>.做完后立即分享给了两个朋友,他俩都被吓坏了.现在分享给 ...