goto 可在同一函数内跳转到带标签的语句。日常控制流宜使用结构化语句;在 C 语言缺少异常机制的情况下,将多处失败路径汇聚到单一清理点,是 goto 的常见合理用途,常与错误处理及动态内存释放配合。
goto 语法
goto label;
label:
/* 跳转目标 */滥用 goto 会使控制流难以跟踪;宜限制在错误恢复等少数模式中使用。
简单分支示例
除零时跳转到统一处理代码:
#include <stdio.h>
int main(void) {
int numerator = 10;
int denominator = 0;
int result;
if (denominator == 0) {
goto excep;
}
result = numerator / denominator;
printf("%d\n", result);
excep:
printf("Exception: Division by zero is not allowed!\n");
return 0;
}单一清理出口
打开文件、读数据等多步操作中,任一步失败时均可跳转到同一标签释放资源:
#include <stdio.h>
int main(void) {
FILE *file = NULL;
int result = 0;
file = fopen("example.txt", "r");
if (file == NULL) {
printf("Error opening file\n");
goto error;
}
result = fread(NULL, 1, 100, file);
if (result == 0) {
printf("Error reading file\n");
goto error;
}
printf("Successful\n");
error:
if (file != NULL) {
fclose(file);
}
return 0;
}与在每个分支重复编写 fclose 相比,集中清理可降低遗漏释放的概率。
其他合理用途
- 多步
malloc失败时跳转到统一free序列。 - 从深层嵌套循环中跳出外层(亦可权衡是否重构为函数)。
- 在大型函数末尾统一返回前的收尾逻辑。
使用限制
- 不宜用
goto替代常规的循环与条件结构。 - 跳转不得越过变量的初始化进入其作用域(C99 及以后规则须遵守)。
- 跨函数跳转须使用
setjmp/longjmp等机制,与goto不同。
本节说明了 goto 在错误清理中的典型模式。下一节介绍信号的捕获与处理。