淺析C語言中的goto語句
來源:用戶上傳
作者:
摘要:本文介紹了goto語句之爭的歷史背景,舉例分析了C語言中goto語句在處理的某些問題上的優勢,并提出靈活替換goto語句的一個思路,反駁了傳統觀點中對goto語句的偏見。
關鍵詞:goto語句;do-while(0);錯誤處理;循環跳出;程序可讀性
Goto語句,又稱為無條件轉移語句,一直以來都飽受編程從業者的詬病,似乎成了行業內的敏感詞。人們總是談goto色變,上課時老師也會告誡你不要輕易去用goto語句。但是真的是這樣嗎?為什么大家都如此避諱goto語句呢?
1 歷史上的兩大爭論
要了解人們回避goto語句的原因就必須了解goto語句的發展歷史。
爭論起源:
1968年,E.W.Dijkstra發表了有名的《Go to Statement Considered Harmful》,提出“goto語句是有害的”論點,激起了人們對傳統程序設計方法的討論。
爭論出現兩種聲音。主張從高級程序語言中廢除goto語句的人覺得,goto語句百害而無一利,他們認為:goto語句會造成程序靜態結構和動態執行之間巨大的差異,并且破壞了程序單入口單出口的基本結構,難以查錯。而去掉goto則能使程序更加易讀和理解。
而另一類人認為,若廢除goto語句,某些情況下反而會增加許多程序不必要的計算量,使程序變得復雜,而靈活地使用goto語句會提高程序的效率。
爭論平息:
1974年,D.E.Knuth發表了文章《Structured Programming With GOTO Statement》,發表了客觀的觀點:在一些使用goto會使程序變得難以理解的情況下,要避免使用goto語句,因此還限制goto語句不能從一個模塊跳轉到另一模塊;但在不破壞程序良好結構的前提下,有控制地使用一些goto語句來提高程序的效率是可以的。這種觀點的提出才平息了這場長達10年之久的爭論。
隨著后來Dijkstra和他的研究團隊證明了所有程序都可以用順序、分支和循環結構來描述,結構化程序設計思想深入人心,goto語句漸漸淡出了人們的視線。
2 考慮使用goto語句的一些情形
了解了goto語句的歷史,我們就知道了goto語句為何受大部分編程相關人員所“唾棄”,并不是goto語句本身有悖于程序本身,究其根本,使用goto語句會加大程序員們的閱讀難度。這直接導致代碼難以理解和發現錯誤。所以,在根本上程序員們所“唾棄”的是難以理解的程序而不是goto語句,如果合理使用goto語句使程序易于理解,那么使用goto語句不但不會被編程人員所禁忌甚至可能會很受歡迎。下面介紹幾種適合使用goto的情形。
(1) 一個函數需要多次執行同一程序片段
當在一個函數中的幾個地方要用到一個程序片段,而又沒有將其包裝成函數的必要,但把該片段在每個需要的地方復制粘貼又會使代碼變的冗余時,這時候使用goto就很有價值。 最常見的例子就是進行錯誤處理。當程序查錯成功時,函數需要返回進行錯誤處理,常見的處理方法是跳轉到程序結尾,釋放資源。而如果在一個函數中有多個錯誤處理,若不使用goto語句,就不可避免地會在每處錯誤下展開處理內容,例如下面這段代碼:
可見,goto語句在這里不但沒有造成麻煩反而提高了程序的質量,使程序變得更條理更易于理解。
?。?) 從多層循環中跳出到循環外部
眾所周知,在C語言中,要想從一個循環內部跳出到循環外部,最常用的方法是使用break關鍵字。但是break一次只能跳出一層循環,當需要從多層循環直接跳出到循環外部時,break就顯得有點捉襟見肘了。你只能在每層循環里都寫一次break,這無疑降低了程序的效率。這時候goto的作用便顯現出來了,使用goto語句可以輕而易舉地從重重循環嵌套中脫身。以下代碼作為一個例子:
上述代碼只是較為簡單的三層循環,在規模較復雜的程序中多層循環應用得更加廣泛,這時使用goto語句更勝一籌。但要注意一步到位,避免重復使用對其他功能造成影響。
?。?)提高程序的可讀性
盡管goto語句被人詬病最多的就是使程序難以被閱讀和查錯,但它某些情況下反而可以用來增加程序的清晰度。在上述前兩對例子里我們就能夠從中看出這一點。在第一個示例代碼中,程序中的錯誤處理過程顯得十分凌亂。而在使用goto語句后,無論從視覺還是邏輯上,整個程序都顯得十分條理,井然有序;另一對例子也反映了該問題,使用break的那段代碼明顯不如使用goto語句的代碼更容易看出程序的意圖。由此看來,goto語句反而使程序變得更加容易閱讀和理解。
另一方面,goto語句還可以充當“注釋”。例如我們在編寫程序的時候有時會遇到一大段比較亂的代碼,比如說字符集,不能優化的功能性片段等等。遇到這樣的情況,就可以利用goto語句的標簽將這段標記出來,易于編程者明確該片段的功能,方便其閱讀代碼。這種情況下,goto語句的使用不再是為了跳轉到某處,而是起一個“注釋”的作用,使程序變得更加清晰。
3 goto語句的一個替代思路
對goto語句有了如上的認識后就會明白,無條件反對goto語句根本不是明智之舉,在一些情況下使用goto能夠使編程事半功倍而并不破壞程序原有的結構性。goto的使用不僅僅是使用一個語句,而是一種解決問題的思路和編程習慣。有這樣思考方式的人,即使不用goto也能探索出類似goto的邏輯來。以我在第二部分的第一個例子來講,使用goto能夠更好地解決錯誤處理問題,但有一個前提就是所有的變量定義必須要在goto之前,所以一般將變量全部放在函數頭部定義。可是當函數規模較大時,有很多臨時需要的變量并不能預期定義在goto語句之前,這就需要用新的機制來替換goto。在C++、JAVA等中我們可以考慮用異常處理機制來替換,而在C語言中,可以使用do-while(0)的方法替換goto,從而消除對變量的限制。例如第二部分第一個例子的程序可以改寫成:
4 總結
綜上所述,goto語句不應該隨波逐流地被認為是一種“異類”,它本身并沒有錯,Dijkstra以及之后的人極力反對它是因為泛濫地使用goto將會導致軟件難以理解和跟蹤。我們要抵制的是難以理解和跟蹤的程序而并不是goto語句本身。從上面的論述也可以知道,在恰當的情況下使用goto語句是會讓程序更易于理解和跟蹤的。如果不能夠理解這一點,即使不使用goto語句,也有可能寫出更為糟糕的代碼。我們的出發點是:構造清晰易懂的代碼。goto和其它語句及機制一樣,都只是為我們這個思想服務的手段或工具。
參考文獻
[1]于延,周國輝.C語言程序設計案例教程[M].清華大學出版社,2016.
[2]侯衛周,郭浩,王娟玲.C語言結構化程序設計與GOTO語句之間的關系[J].平頂山學院學報,2006,21(2):32-34.
[3]Dijkstra E W.Go to statement considered harmful[J].Communications of the Acm,1968,11(3):147-148.
[4]Knuth,Donald E .Structured Programming with go to Statements[J].ACM Computing Surveys,1974,6(4):261-301.
轉載注明來源:http://www.hailuomaifang.com/1/view-14850403.htm