首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

goto 並非洪水猛獸:合理使用場景與最佳實踐

     編輯:關於C語言

歷史包袱與現代共識

1968 年 Dijkstra 《Go To Statement Considered Harmful》確立「結構化程式設計」正統地位。但 **Linux 內核、Windows 核心、嵌入式固件、編譯器後端** 大量使用 goto。關鍵在於:**結構化構造無法優雅表達的控制流**,而非濫用。

兩大經典合理場景

1. 多層巢狀迴圈的「一次性跳出」


// 無 goto:需多層 flag 或函數提前 return
bool found = false;
for (int i=0; i

優勢:避免汙染外層作用域的旗標變數,減少分支預測失誤,標籤語意明確(FOUND/ERROR/CLEANUP)。

2. 資源獲取即初始化(RAII)缺失時的「統一錯誤清理」

C 無建構/解構、無 try/finally、無 defer。goto cleanup 是 **業界標準模式**(Linux 內核、Windows 驅動、OpenSSL、FFmpeg 等)。


int init_device(Device *dev) {
    int ret = -1;
    dev->reg = map_registers();
    if (!dev->reg) goto err_map;
    dev->irq = request_irq();
    if (dev->irq < 0) goto err_irq;
    dev->buf = alloc_buffer(SIZE);
    if (!dev->buf) goto err_buf;
    ret = 0; // 成功
err_buf:
    if (dev->irq >= 0) free_irq(dev->irq);
err_irq:
    unmap_registers(dev->reg);
err_map:
    return ret;
}

核心原則:

  • 標籤**逆序**對應資源獲取順序(後獲取先釋放)。
  • 每個錯誤路徑僅跳轉到對應清理點,**無重複釋放代碼**。
  • 成功路徑自然落下,ret=0 後不進入任何 err_* 標籤。

微軟官方範例驗證

MSXML SDK 範例程式碼大量使用 goto clean; 釋放 COM 介面、BSTR、VARIANT、關閉 COM 庫。這是 Microsoft 內部編碼規範認可的模式。

濫用反模式(堅決避免)

  • 向前跳轉構造迴圈(用 while/for)。
  • 在同一函數內跳來跳去形成「麵條代碼」。
  • 跨函數 goto(C 不支援,C++ 更不可能)。
  • 用 goto 替代早期 return(現代編譯器優化後等效,但 return 可讀性更高)。

編碼規範建議

  1. **預設禁用** goto,靜態分析工具標記。
  2. **白名單例外**:錯誤清理鏈、多層迴圈跳出、狀態機實現(如解析器)。
  3. **命名規範**:標籤全大寫 + 下劃線 ERR_XXX/CLEANUP_XXX,放在函數尾部。
  4. **代碼審查強制說明**:每個 goto 必須有註釋解釋「為何結構化寫法更差」。

名言致敬

「goto 少用、慎用,但不能禁用。」—— Donald Knuth, Structured Programming with go to Statements (1974)

工程師的成熟標誌不是死記規則,而是**理解規則背後的權衡**,在合適時機選擇最清晰、最安全的表達。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved