goto 標籤名;
...
標籤名: 語句;
goto 無條件跳轉到同一函數內的標號語句。setjmp/longjmp)。
if (strlen(str) < 10) goto Label1;
else goto Label2;
Label1:
printf("不足10字符");
goto Label3;
Label2:
printf("達到或超過10字符");
goto Label3;
Label3:
getchar(); return 0;
while (1) {
i++;
printf("%d\n", i);
if (i == 10) goto AAA;
}
AAA: printf("OK!\n");
無需設置標誌變量逐層 break,直接跳出。
AAA:; // 空語句,僅一個分號
標號必須後跟一條語句,空語句 ; 滿足語法要求。
| 觀點 | 支持 | 反對 |
|---|---|---|
| 可讀性 | 簡化特定邏輯(錯誤處理、狀態機) | 導致「麵條代碼」,難以追蹤流程 |
| 結構化編程 | Dijkstra「Go To 有害」針對濫用 | 現代語言提供更好替代(異常、協程) |
| 性能 | 編譯器優化後等價 | 無顯著優勢 |
| 適用場景 | 錯誤清理統一出口、狀態機、跳出多層循環 | 一般控制流應用 if/for/while/function |
int func() {
int *p = malloc(...);
if (!p) goto err1;
FILE *f = fopen(...);
if (!f) goto err2;
// 正常邏輯
fclose(f);
free(p);
return 0;
err2:
free(p);
err1:
return -1;
}
break/continue/return/函數提取。cleanup:、error_exit:、done:。| 場景 | goto 方案 | 結構化替代 |
|---|---|---|
| 多層循環跳出 | goto label | 提取為函數用 return / 設置標誌變量 |
| 資源獲取失敗清理 | goto cleanup | RAII (C++), defer (Go), try-with-resources (Java) |
| 狀態機 | goto state_label | switch 狀態表 / 函數指針表 / 協程 |
goto 是 C 語言提供的非結構化跳轉原語。現代共識:不禁用,但嚴格限制用途。在「資源獲取失敗時的逆序清理」與「跳出深層巢狀循環」兩大場景中,goto 往往比結構化替代方案更簡潔、高效、不易出錯。除此之外,應優先使用結構化控制流構造,保持代碼可讀與可維護。