本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第3章,建议25,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
建议25:尽量避免使用goto语句
自从提倡结构化程序设计以来,goto 语句就成为业界争议最大的语句。不论各家对goto 语句的意见是好是坏,总结前人的经验,还是应该尽量避免在程序中使用goto语句,其原因主要有以下两方面。
首先,由于goto 语句可以灵活跳转,如果不加限制,它的确会破坏结构化设计风格,如下面的示例代码所示:
A:
/*处理代码*/
goto B;
/*处理代码*/
goto C;
B:
/*处理代码*/
goto A;
/*处理代码*/
goto C;
C:
/*处理代码*/
goto A;
/*处理代码*/
goto B;
很显然,上面的示例代码已经能够说明问题了,随着标签数量增多,将给代码的可读性、可调试性与可维护性带来一场灾难。
其次,若不加限制地使用goto语句,该语句可能跳过变量的初始化、重要的计算等语句,从而给程序带来灾难性的错误与潜在的安全隐患,如下面的示例代码所示:
char *p = NULL;
/*处理代码*/
goto state;
/*变量sum被goto 跳过*/
int sum = 0;
/*指针p被goto 跳过,没有分配内存*/
p = (char *)malloc(40 * sizeof(char));
if (p == NULL)
{
/*处理代码*/
}
/*处理代码*/
state:
/*使用p指向的内存里的值的代码*/
/*使用变量num*/
如上面代码所示,如果编译器不能发现此类错误,则每用一次goto 语句都可能导致程序出现灾难性的错误与潜在的安全隐患。
当然,如果遇到下列情况,goto 语句还是有其自身优势的。
for(...)
{
for(...)
{
for(...)
{
/*使用goto语句跳出循环,执行其他的语句*/
goto A;
}
}
}
A:
/*处理代码*/
在上面的代码中,如果使用break语句,则只能跳出单层的循环;如果使用return语句,则会跳出整个函数,无法继续执行其他的代码。因此,这里可以使用goto语句。其实,如果陷入很深层次的循环中想要跳出最外层的循环,用 goto 直接跳出比用 break 一层循环一层循环跳出要好得多。