《浅谈结构化程序设计与goto语》由会员分享,可在线阅读,更多相关《浅谈结构化程序设计与goto语(9页珍藏版)》请在金锄头文库上搜索。
1、浅谈结构化程序设计与GOTO语句魏为民摘要:本文讨论了结构化程序的基本特征,提出了goto语句在某些特殊情况下的程序设计中的一些用处。关键词:结构化程序;goto语句;程序设计优化;程序可读性;程序加密。荷兰学者Dijkstra提出了“结构化程序设计”的思想,它规定了一套方法,使程序具有合理的结构,以保证和验证程序的正确性,这种方法要求程序设计者不能随心所欲地编写程序,而要按照一定的结构形式来设计和编写程序,它的一个重要目的是使程序具有良好的结构,使程序易于设计,易于理解,易于调试修改,以提高设计和维护程序工作的效率。在Djakstra的时代,goto语句曾经引发了一场规模不小的争议,从那以后
2、,goto就不被程序员青睐了。虽然到了最后,人们并没有把goto 语句处以极刑,然而亦鲜有人撰文提及goto 语句的用处,我们只能读到关于goto语句弊病的文章。在各种程序设计教科书上几乎都提到了goto ,并且青一色地建议其读者在编程时不用goto语句,因为:“可以证明,任何一个程序都可以使用三种基本的结构来构成,goto语句是多余的”。很可能再过几年人们就将忘记当今各种程序设计语言中几乎都具备的goto 语句了。在本文中,结合本人的一些编程经验,谈谈 goto 语句在某些特殊情况下的程序设计中的用处。一、结构化程序设计的基本特征结构化程序设计(Structured Programming)
3、是荷兰学者E.W.Dijkstra等人在研究的人的智力局限性随着程序规模的增大而表现出来的不适应之后,于1969年提出的一种程序设计方法,这是一种复杂任务时避免混乱的技术。提出了把程序结构规范化的主张,要求对复杂问题的求解过程应按我们大脑容易理解的方式进行组织,而不是强迫我们的大脑去接受难以忍受的冲击。具体来说,结构化程序设计的思想包括以下三方面的内容:(1)程序由一些基本结构组成。任何一个大型的程序都由三种基本结构所组成,由这些基本结构顺序地构成了一个结构化的程序。这三种基本结构为:顺序结构(如下图(1)所示),选择结构(亦称分支结构,如下图(2)所示)和循环结构(如下图(3)所示)。图1顺
4、序结构图 图2选择结构图 图3循环结构图同时结构化定理还进一步表明,任何一个复杂问题的程序设计都可以用顺序、选择和循环这三种基本结构组成,且它们都具有以下特点:只有一个入口;只有一个出口;结构中无死循环,程序中三种基本结构之间形成顺序执行关系。(2)一个大型程序应按功能分割成一些功能模块,并把这些模块按层次关系进行组织。(3)在程序设计时应采用自顶向下逐步细化的实施方法。按结构化程序设计方法设计出的程序优点是:结构良好、各模块间的关系清晰简单、每一模块内都由基本单元组成。这样设计出的程序清晰易读,可理解性好,容易设计,容易验证其正确性,也容易维护。同时,由于采用了“自顶向下、逐步细化”的实施方
5、法,能有效地组织人们的智力,有利于软件的工程化开发。 二、Goto语句与程序设计优化任何一个结构化程序在编译以后都是需要用机器语言中的直接转移指令语句(同goto完全是一回事)来实现其结构的。在编译时,编译系统常常为了对程序进行优化而加入直接转移指令。其实,在使用高级语言编写程序的阶段,在不影响程序可读性的前提下,我们仍然有可能使用goto语句优化程序,提高程序的运行效率,减少代码的冗余。我们可以举出很多使用goto 优化程序的例子,比如以下的case结构中经常使用的一种模型:程序模型A:switch (Variable)case Value1:Do specific Value1 here;
6、goto CommonCaseProcess;case Value2:Do Value2 here;break;case Value3:Do specific Value3 here;goto CommonCaseProcess;case Value4:Do specific Value4 here;CommonCaseProcess:Do Common Process here;break;这样写程序是由于case Value1, case Value3, case Value4的处理代码中最后阶段要做相同的事情。如果不使用goto 语句,则有如下两种等效的解决办法:程序模型B:switch
7、 (Variable)case Value1:Do specific Value1 here;Do Common Process here;break;case Value2:Do Value2 here;break;case Value3:Do specific Value3 here;Do Common Process here;break;case Value4:Do specific Value4 here;Do Common Process here;break;程序模型C:void CommonProcess(parameters)Do common process here;re
8、turn;switch (Variable)case Value1:Do specific Value1 here;CommonProcess(parameters);break;case Value2:Do Value2 here;break;case Value3:Do specific Value3 here;CommonProcess(parameters);break;case Value4:Do specific Value4 here;CommonProcess(parameters);break;不难看出,从结构化程序设计的观点上看,程序模型B和程序模型C都具有优良的可读性。但
9、是,程序B存在代码冗余,如果要更改case Value1, case Value3 和case Value4 的共同处理的部分,需要同时改变三处相同的代码段,这在程序设计中是很忌讳的。程序模型C使用一个函数调用解决了代码冗余的问题,然而,增加了函数调用的程序运行时间开销和堆栈空间开销,在效率上不如程序模型B。程序模型A的风格稍差,但从优化程序的角度上看,它结合了程序模型B和程序模型C的优点。由于使用了goto语句,省去了函数调用,没有函数调用的时间开销和空间开销,最多只存在执行直接转移指令所带来的可忽略不计的时间开销(实际上编译系统均会对类似于程序模型B的程序段进行优化,结果会同程序模型A一模
10、一样,这样程序模型A的效率同程序模型B的效率是相同的);并且只使用一段代码解决case Value1, case Value3, case Value4的共同部分,没有代码冗余。程序模型A所付出的代价是使用了goto 语句。不过,基于如下的理由,可以认为这个goto 语句的使用不会对程序的可读性造成致命的破坏:(1) goto 语句被严格限制在case结构内。首先,case 结构是很灵活的一个结构,它可以有多个出口,我们也常常使用如下的技巧来实现需要使得两个不同的case有相同的处理的情况:case a:case b:do something here;break;这样,作为case 结构的多
11、出口的补充,我们实现了使case a 与 case b有相同的出口。而程序模型A使用的goto语句,是对这种相同出口技巧进一步的补充;其次,goto 语句只在case 结构内使用,所跳转到的位置也在case 结构内,它不会照成大面积的跳转,使程序的阅读者晕头转向;于是,我们可以认为,在程序模型A中的goto 语句,增加了case 结构的功能。(2) goto 语句都跳某一共同程序段,并且都是往case结构的出口方向前进。这就保证了带goto 语句的程序的可读性。以此例可看出,goto 语句能提高程序的效率,但未必必须付出破坏程序可读性的代价。三、Goto语句与提高程序可读性用goto语句还能提
12、高程序可读性?回答是肯定的。滥用goto是会破坏程序的可读性,但合理地使用goto语句,除了能提高程序的效率外,还是有可能增加程序的可读性的。比如,我们经常会遇到类似这样的程序设计问题:要求用户输入一个整数,如果用户输入的整数的值在0到9之间,则让程序完成某个功能,否则要求用户重新输入。如果不用goto语句,任何人都会把程序写成如下的样子:程序A:int iInput;doscanf(“%d”,&iInput); while (iInput 9);这段程序用了循环结构,从而避免了goto 语句。如果可以使用goto 语句,则可将程序写成这样:程序B:int iInput;GetUserInpu
13、t:scanf(“%d”,&iInput);if (iInput 9) goto GetUserInput;显然,第二段程序是在现今的程序设计教科书中见不到的,因为它不是结构化的。用结构化程序设计风格设计的程序具有良好的可读性,但这并不代表风格好的程序都是用了结构化的方法。对于程序A,直观地说,它的意思是:程序开始后进入一个循环,循环结束的条件是变量iInput的值在0与9之间,而在循环体内要求用户输入iInput的值;而程序B的直观意义是:要用户输入iInput,如果iInput的值小于0或者大于9,则跳回原先要用户输入iInput的程序段,否则程序继续运行。这两段程序的执行结果完全一样,但
14、显然使用了goto语句的非结构化的程序B同题目的要求在描述上更为一致。为了获得结构化的程序,我们不得不对原先的描述进行转化:从描述():“要求用户输入一个整数,如果用户输入的整数的值在0到9之间,则程序继续运行,否则要求用户重新输入。”转化到描述():“一直做这样的一件事:要求用户输入一个整数,除非用户输入的数在到之间。”这样的转化使得计算机语言同人类语言之间又多了一层隔阂。因为,描述()是人类语言最自然的表达方法,却不是结构化程序设计方法所能表达的;描述()是用人类语言描述的结构化方法所能接受的直接表达,但对人类来说其含义不如描述()直观,不容易理解。在人类阅读上面的两段程序时,程序A给人传
15、达的是描述(),程序B传达给人的是描述(),也就是说,程序B更容易被人类理解,非结构化的、用了goto语句的程序B更具可读性。计算机科学家们一直在努力,使计算机语言接近人类的语言。但在实现这样的梦想以前,如果goto 语句在某些场合能使计算机程序更接近人类语言,我们何不用它!再举个例子:这是微软的MFC类库中的一段源程序(稍微做了简化),其作用是做MFC应用程序的初始化工作,如果所有的初始化工作成功,则进入线程的运行,否则,只要在初始化过程中有一步失败,就直接退出。其中所用的goto 语句不仅提高了程序的可读性,也简化了程序的编写。int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)int nReturnCode = -1;CWinThread* pThread = AfxGetThread();CWinApp* pApp = AfxGetApp();if (!AfxW