程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 【編程好習慣】恰當使用goto語句

【編程好習慣】恰當使用goto語句

編輯:關於C語言

goto語句在C/C++語言中可謂是“臭名昭著”,乃至有的書或公司的編程規范)提出禁用goto語句的說法。其結果就是,造成有的程序員一看到goto語句在某程序中被使用,就本能地認為這個程序寫得很“垃圾”。此外,也使得有些程序員因為使用了goto語句而覺得自己很不專業。其實,凡事都不能太偏激,goto語句運用得好能大大地簡化程序,以及提高程序的可讀性和可維護性。在開始示例其好處之前,先用一些統計數據來說明goto語句並沒有因為“臭名昭著”而被拋棄,這些統計數據可能並不是百分之百的精確,但很具有說服力。對於操作系統,Linux-2.6.21內核使用了20,333個goto語句,VxWorks-6.2則使用了9142個,最後941個goto語句被運用到了rtems-4.9.2中;另外,glibc-2.9庫使用了1750個goto語句。所有這些統計數據都表明,goto語言並沒有想象的那樣可怕而招到禁用,其關鍵在於 —— 恰當地運用它。

圖1是一個沒有采用goto語句編寫的函數,其中存在多處出錯處理的代碼,比如113~115行、120~122行和126~129行。采用這種分布式的出錯處理,很容易出現遺漏釋放前面已經分配的資源,從而造成資源洩漏問題。如果采用goto語句,則能取得更好的效果。

example.c
00097: int queue_init (queue_t ** _pp_queue, int _size)
00098: {
00099:     pthread_mutexattr_t attr;
00100:     queue_t *queue;
00101:
00102:        queue = (queue_t *) malloc(sizeof(queue_t));
00103:        if (0 == queue) {
00104:         return -1;
00105:     }
00106:     *_pp_queue = queue;
00107:
00108:     memset (queue, 0, sizeof (*queue));
00109:     queue->size_ = _size;
00110:
00111:     pthread_mutexattr_init (&attr);
00112:     if (0 != pthread_mutex_init(&queue->mutex_, &attr)) {
00113:         pthread_mutexattr_destroy (&attr);
00114:         free (queue);
00115:         return -1;
00116:     }
00117:
00118:     queue->messages_ = (void **) malloc (queue->size_ * sizeof (void *));
00119:     if (0 == queue->messages_) {
00120:         pthread_mutexattr_destroy (&attr);
00121:         free (queue);
00122:         return -1;
00123:     }
00124:
00125:     if (0 != sem_init(&queue->sem_put_, 0, queue->size_)) {
00126:         free (queue->messages_);
00127:         pthread_mutexattr_destroy (&attr);
00128:         free (queue);
00129:         return -1;
00130:     }
00131:
00132:     pthread_mutexattr_destroy (&attr);
00133:
00134:     return 0;
00135: }圖1

圖2是采用goto語句所編寫的另一個版本,與不采用goto語句的版本相比,程序更加的簡單,且在出錯處理的地方大都使用goto語句跳轉到程序的末尾進行處理。goto語句除了可以用在這裡所示例的出錯處理中,還可以用在其它的程序邏輯中以簡化程序並提高閱讀性。

example.c
00053: int queue_init (queue_t ** _pp_queue, int _size)
00054: {
00055:     pthread_mutexattr_t attr;
00056:     queue_t *queue;
00057:
00058:     queue = (queue_t *) malloc(sizeof(queue_t));
00059:         if (0 == queue) {
00060:         return -1;
00061:     }
00062:     *_pp_queue = queue;
00063:
00064:     memset (queue, 0, sizeof (*queue));
00065:     queue->size_ = _size;
00066:
00067:     pthread_mutexattr_init (&attr);
00068:     if (0 != pthread_mutex_init(&queue->mutex_, &attr)) {
00069:         goto error;
00070:     }
00071:
00072:     queue->messages_ = (void **) malloc (queue->size_ * sizeof (void *));
00073:     if (0 == queue->messages_) {
00074:         goto error;
00075:     }
00076:
00077:     if (0 != sem_init(&queue->sem_put_, 0, queue->size_)) {
00078:         goto error1;
00079:     }
00080:
00081:     pthread_mutexattr_destroy (&attr);
00082:
00083:     return 0;
00084:
00085: error1:
00086:     free (queue->messages_);
00087: error:
00088:     pthread_mutexattr_destroy (&attr);
00089:     free (queue);
00090:     return -1;
00091: }圖2

使用goto語句時需要注意以下原則:
1) 不要過份地使用。比如圖2中的60行就沒有采用goto語句跳到程序的最後面,之所以這裡不使用goto是為了閱讀方便。因為程序此時還沒有分配資源,所以直接返回顯得更加的直接了當。還有就是,在這個函數中如果存在使用goto語句都意味著出錯了且需要釋放資源。如果將60行的語句也改為goto就破壞了這個函數中使用goto語句的一致性。
2) 不要讓goto語句形成一個環。使用goto語句應形成一條線,從一點跳到另一點。當然,如果goto語句的使用沒有破壞可讀性,那可以適當的考慮打破這一原則。

本文出自 “至簡李雲” 博客,請務必保留此出處http://yunli.blog.51cto.com/831344/248828

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved