1968 年 Dijkstra 《Go To Statement Considered Harmful》確立「結構化程式設計」正統地位。但 **Linux 內核、Windows 核心、嵌入式固件、編譯器後端** 大量使用 goto。關鍵在於:**結構化構造無法優雅表達的控制流**,而非濫用。
// 無 goto:需多層 flag 或函數提前 return
bool found = false;
for (int i=0; i
優勢:避免汙染外層作用域的旗標變數,減少分支預測失誤,標籤語意明確(FOUND/ERROR/CLEANUP)。
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 可讀性更高)。goto,靜態分析工具標記。ERR_XXX/CLEANUP_XXX,放在函數尾部。goto 必須有註釋解釋「為何結構化寫法更差」。「
goto少用、慎用,但不能禁用。」—— Donald Knuth, Structured Programming with go to Statements (1974)
工程師的成熟標誌不是死記規則,而是**理解規則背後的權衡**,在合適時機選擇最清晰、最安全的表達。