Goto真的是邪恶的吗?
很早以前的文章,翻出来让大家评价评价
有常用goto的吗
几日前在Cafe午餐的时候,大家聊起一些在Windows操作系统源代码库中曾经看到过的一些趣闻逸事,比如那个著名的“because Exchange is a moron”(正好这天公司的Exchange服务器巨慢,所以大家更是大发一笑)的注释。这其中有人提到Windows代码中大量使用goto语句的这个事,这让我想起这样一个有趣的问题:
在程序代码中,我们为什么使用goto,或者,我们为什么不该使用goto呢?
我曾经不止一次地听某某义正言辞地向我宣传goto是邪恶的,但如果我追问这么说的理由为何时,通常的答案都是模模糊糊的人云亦云之类的回答。大部分的理由都会指出goto破坏了程序的可读性和可维护性,如果代码里到处都是goto来goto去,到最后谁都很难搞清程序goto到哪一个地方了。
这看似颇有道理的说辞其实充满了迂腐的书生气。稍微有点常识的程序员,难道真会如此到处使用goto么?显然不会。如果说真的有那么一位程序员是到处在用goto把他的程序逻辑拼接起来的话,那我想他不是天才(汇编写太多了,到处都要自己跳转)就是无知(完全无法结构化自己的算法思路)。而软件开发作为一个工程行业经过这么多年的发展,现实中已经很少会真的有这种滥用goto的现象了。这当然也要感谢于那些关于goto邪恶性的大力宣传,大家上procedural programming第一课开始,就被反复灌输了“不要用goto,不要用goto”的观念。
那为什么Windows操作系统代码中大量使用了goto?是不是微软总部都雇佣了些烂人,大家都在混饭吃?还是说对于goto的使用是其实很有选择性的?而从当年goto的大量出现到今天这个关键词在使用C#或Java写就的程序中几乎绝迹,这一切,其实都是有其历史背景和含义的?
要回答这些问题,我们首先讨论一下goto在Windows操作系统源码中的使用。如果仔细观察一下的话,你会发现goto的使用其实都是在一种很特定的场合,那就是:系统资源的回收和释放。这里,系统资源可能是一块字符串内存,可能是某个内核对象(比如event或mutex)的句柄(handle),也可能是更复杂一些的数据结构。所以,goto出现的代码段,通常有这样的结构:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/void Func()...{... Magic::Initialize();BSTR someString = ::SysAllocString(L"Some random string");hr = CallSomeAPI();if (FAILED(hr))goto EXIT; ...hr = CallSomeOtherAPI(); if (FAILED(hr))goto EXIT;...EXIT: Magic::Uninitialize();::SysFreeString(someString);...}Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/HRESULT Func(){ ... Magic::Initialize(); BSTR someString = ::SysAllocString(L"Some random string"); hr = CallSomeAPI(); if (FAILED(hr)) { Magic::Uninitialize(); ::SysFreeString(someString); return hr; } ... hr = CallSomeOtherAPI(); if (FAILED(hr)) { Magic::Uninitialize(); ::SysFreeString(someString); return hr; } ... return S_OK;}
Windows平台下感觉用__try ... __finally来实现清理资源更简单
[解决办法]
楼主举的例子可以用do...while(false)代替,当然,这里用goto是最明确的,用do...while(false)的话,有些个基础比较差的人你还得个他解释一下为什么
[解决办法]
goto至少有两种典型应用场景,这些场景下,goto是最优雅的解决方案之一
1.多层循环跳出,如果为了避免goto而罗嗦一大堆,那是神经病
2.楼主举的资源释放的例子,如果不用goto或do...while(false),反而极易引入bug,代码也混乱
这都是很基础的应用,之所以大部分应试者都不知道,只能说水平和经验还有差距,这是大学应届生和初级程序员的普遍现象
[解决办法]
高手用goto:合理
新手用goto:万恶
[解决办法]
Magic::Uninitialize();
::SysFreeString(someString);
这两个可以合并到一个函数中嘛。 这样就可以去掉goto了。
不推荐goto是怕滥用或者乱用。
[解决办法]
goto挺好,和异常处理也不冲突
[解决办法]
for (int i = 1; i < 2; i++) { }
[解决办法]
用goto的人大概都很喜欢_JMP。
[解决办法]
因为宇宙里面有γ射线。
[解决办法]
万恶的不是某种模式,万恶的是不可控的状态。没有什么模式是不可控的,但也没有任何一种模式是不会陷入不可控状态的。