嵌入式C中的 goto 语句,争议很大
内容提要
在C语言中,goto语句是一种跳转语句,用于无条件地跳转到代码中的其他标签处。然而,由于降低了代码的可读性和增加了复杂性,程序员很少使用它。许多编程语言已经引入了函数的概念,取代了goto语句。尽管如此,一些编程任务仍难以在不使用goto语句的情况下实现。因此,一些语言提供了类似于goto的控制流语句,如break和continue。然而,使用goto语句会破坏程序结构,降低可读性,因此被不推荐使用。在某些情况下,可以考虑使用goto语句,如从多重循环中直接跳出、出错时清除资源和增加程序清晰度的情况。
延伸解读
goto 争议的历史根源
文章提到,goto 的争议可追溯到 Dijkstra 1968 年的论文《GOTO陈述有害轮》,他认为不加限制地使用 goto 会使程序正确性分析和验证复杂化。同时,高德纳在《Structured Programming with go to Statements》中分析指出,某些常见编程任务使用 goto 反而能得到最理想的结构。这反映了争议的核心:goto 并非绝对有害,关键在于是否受限和恰当使用。
现代语言对 goto 的替代与保留
许多语言提供了受限的跳转语句,如 break 和 continue,它们只能跳到循环块结束或继续下一循环。switch/case 结构则高效实现了多路 goto。Java 不支持 goto,C# 却支持,并认为 goto 可保证程序唯一出口,避免过大的 if 嵌套。C/C++ 保留了 goto,但建议少用。这些差异说明,goto 的存废取决于语言设计对可读性与控制灵活性的权衡。
可谨慎使用 goto 的典型场景
文章指出,在从多重循环中直接跳出、出错时清除资源、以及可增加程序清晰度的情况下,可以考虑使用 goto。Linux 内核代码中就有使用 goto 的例子,例如 i2c-dev.c 的初始化函数,用 goto 集中处理错误清理。但文章强调,这些使用非常谨慎,基本遵循同一函数内跳转、避免复杂跳转等原则,并非随意滥用。
使用 goto 的风险与原则
不加限制地使用 goto 会破坏清晰的程序结构,降低可读性,甚至产生“面条代码”。它可能跳过对象构造、变量初始化或重要计算,带来错误或隐患。文章给出参考原则:只能在同一函数内跳转;起点应是某段小功能的结束处,目标 label 应是另一段小功能的开始处;不能从复杂执行状态中跳出;避免两个方向跳转。遵循这些原则,才能降低 goto 的负面影响。
Q&A
goto语句在C语言中的作用是什么?
goto语句用于无条件地跳转到代码中的其他标签处,改变程序的执行流程。
为什么程序员不推荐使用goto语句?
因为goto语句降低了代码的可读性并增加了复杂性,容易导致不可维护的“面条代码”。
在什么情况下可以考虑使用goto语句?
可以在从多重循环中直接跳出、出错时清除资源或增加程序清晰度的情况下使用goto语句。
哪些编程语言支持goto语句?
C语言和C#支持goto语句,而Java不支持,但将其作为关键字保留。
使用goto语句时有哪些原则需要遵循?
使用goto语句只能在同一函数内,避免复杂跳转,遵循清晰的结构。
goto语句在Linux内核代码中是如何使用的?
Linux内核代码中使用goto语句时非常谨慎,遵循相关原则以保持代码清晰。