How To Use Goto?
看到,网上很多人对于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的威力发挥出来, 就想只有孙悟空才可以发挥金箍棒的威力一样. 使用过程中, 需注意如下:
- 细心的应该发现, 我们所使用的地方,都是在一个函数内部.也就是说, goto, 只在函数内部,** 千万千万千万别goto到其他函数内部. **
- 使用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使用总结
- 团队开发协定函数的错误反馈机制
- goto处理if else的多层嵌套, 将其扁平化处理.
How To Use Goto?的更多相关文章
- 因为没用过,所以没想过的--goto
今天读了读 Rui Maciel 大神写的 mjson parser,mjson 解析器是一个使用 ISO C 实现的小型 JSON 解析器.嵌入式项目中使用到了该解析器,随即拿出来看看. 看到如下代 ...
- bat脚本参数 if goto choice for使用的学习笔记。
写过几次bat脚本,但一直没有总结,最近找到一个网页介绍bat,总结得很好,转自 http://www.jb51.net/article/49627.htm: 本文只总结我不会的,全面的看原网页就可以 ...
- 用goto做异常处理
http://www.cnblogs.com/trying/archive/2012/06/25/2863753.html 今天在CSDN上看到的关于错误返回值的讨论,感觉非常有趣. 从中可以看出被教 ...
- 尽量用goto代替尾递归
void PrintList(List L) { if(L!=Null) { PrintElement(L->Element); PrintLisr(L->Next); } } 所谓尾递归 ...
- C++:为什么说 goto 没有用
要了解一个功能有没有用,首先应该分析它能实现的所有功能. goto 可以实现的功能只有两种:一,向前面跳:二,向后面跳.这两种情况对应三种功能:一,重复执行也就是循环:二,跳过一段代码也就是条件判断: ...
- C语言的傻瓜式随笔(二):全局变量、预编译、goto
函数的作用:可以实现代码的重用. 函数只需要定义1次,那么函数中的代码就可以随意的调用. -某不知出处的基本概念 学而时习之,如有误笔,请指正 一.goto跳转语句 goto在C语言的作用 ...
- GOTO Berlin: Web API设计原则
在邮件列表和讨论区中有很多与REST和Web API相关的讨论,下面仅是我个人对这些问题的一些见解,并没有绝对的真理,InnoQ的首席顾问Oliver Wolf在GOTO Berlin大会上开始自己的 ...
- 辗转相除法求最大公约数,非goto
#include<iostream> using namespace std; //不推荐用goto,当然用它更快 //辗转相除法求两数的最大公约数 int gcd(long int a, ...
- C语言字符串匹配、goto语句、关机命令使用
1.程序执行修改窗口字体颜色命令: 2.程序执行修改窗口标题命令: 3.程序执行关机倒计时命令: 4.根据提示输入团队名称JYHACK TEAM 根据提示输入团队网址:http://bbs.jyhac ...
随机推荐
- Linux学习笔记(7)-进程
明天开始学习进程,在以前的单片机开发中,都没有进程这个概念,但从网上了解到,这个东西在操作系统中似乎具有很重要的地位,一定好好学习! --------------------------------- ...
- windows下node环境配置
1.在node官网上下载合适版本的node安装包,官网地址:http://nodejs.org/#download:我下载的6.5最新版本: 2.安装node,都是系统默认的,一直安装下去: 3.在c ...
- 一场IT民工 与 人贩子 之间的战争 - 感受来自PostgreSQL的爱
标签 PostgreSQL , 图数据库 , 社会关系分析 , 流式分析 , 人贩子 , 图像识别 , 人脸识别 , 公安刑侦 , pipelinedb , stream , neo4j , plpr ...
- Codeforces Round #388 (Div. 2) - B
题目链接:http://codeforces.com/contest/749/problem/B 题意:给定平行四边形的3个点,输出所有可能的第四个点. 思路:枚举任意两个点形成的直线,然后利用这两个 ...
- Android Studio中获取SHA1或MD5的方法
原来在Eclipse中获取SHA1或者MD5,在IDE界面上就可以查找到. 切换到Android Studio后,如何查看呢?找了半天没找到.那就老办法命令行. 第一步.打开Android Studi ...
- POJ 2774 Long Long Message ——后缀数组
[题目分析] 用height数组RMQ的性质去求最长的公共子串. 要求sa[i]和sa[i-1]必须在两个串中,然后取height的MAX. 利用中间的字符来连接两个字符串的思想很巧妙,记得最后还需要 ...
- 深入理解Java的接口和抽象类(转)
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
- C++-Qt【2】-实现一个简单的记事本
用Qt实现一个简单的记事本: #include "helloqt.h" #include <qfiledialog.h> #include <qfile.h> ...
- [BZOJ2072][POI2004] MOS过桥
Description 一个夜晚一些旅行者想要过桥. 他们只有一个火把. 火把的亮光最多允许两个旅行者同时过桥. 没有火把或者多于2个人则不能过桥.每个旅行者过桥都需要特定的时间, 两个旅行者同时过桥 ...
- bzoj4491奇技淫巧线段树
20行的归并+10行的线段树(现在线段树真是越写越短了)+10行主程序(连主程序都缩过行) = =丧心病狂 struct里连开10个,用大括号直接初始化真是爽翻了 #include <cstd ...