linux样式指南提供了使用goto的具体原因,这些与您的示例一致:
https://www.kernel.org/doc/Documentation/process/coding-style.rst
  使用gotos的基本原理是:
  
  
  - 无条件陈述更易于理解和遵循
 
  - 嵌套减少
 
  - 防止在进行修改时不更新单个出口点而导致错误
 
  - 节省了编译器的工作,以优化冗余代码;)
 
  
免责声明我不应该分享我的工作。这里的示例有些虚构,请耐心接受。
这对内存管理很有用。我最近研究了动态分配内存的代码(例如char *,函数返回的代码)。该函数查看路径并通过解析路径的令牌来确定路径是否有效:
tmp_string = strdup(string);
token = strtok(tmp_string,delim);
while( token != NULL ){
    ...
    some statements, some involving dynamically allocated memory
    ...
    if ( check_this() ){
        free(var1);
        free(var2);
        ...
        free(varN);
        return 1;
    }
    ...
    some more stuff
    ...
    if(something()){
        if ( check_that() ){
            free(var1);
            free(var2);
            ...
            free(varN);
            return 1;
        } else {
            free(var1);
            free(var2);
            ...
            free(varN);
            return 0;
        }
    }
    token = strtok(NULL,delim);
}
free(var1);
free(var2);
...
free(varN);
return 1;
现在对我来说,如果您需要添加以下代码,则以下代码会更好,更易于维护varNplus1:
int retval = 1;
tmp_string = strdup(string);
token = strtok(tmp_string,delim);
while( token != NULL ){
    ...
    some statements, some involving dynamically allocated memory
    ...
    if ( check_this() ){
        retval = 1;
        goto out_free;
    }
    ...
    some more stuff
    ...
    if(something()){
        if ( check_that() ){
            retval = 1;
            goto out_free;
        } else {
            retval = 0;
            goto out_free;
        }
    }
    token = strtok(NULL,delim);
}
out_free:
free(var1);
free(var2);
...
free(varN);
return retval;
现在,代码还存在其他各种问题,即N大于10,并且该函数超过450行,并且在某些地方具有10级嵌套。  
但是我提供了我的主管来重构它,我做到了,现在它是一堆都很短的函数,而且它们都具有linux风格
int function(const char * param)
{
    int retval = 1;
    char * var1 = fcn_that_returns_dynamically_allocated_string(param);
    if( var1 == NULL ){
        retval = 0;
        goto out;
    }
    if( isValid(var1) ){
         retval = some_function(var1);
         goto out_free;
    }
    if( isGood(var1) ){
         retval = 0;
         goto out_free;
    }
out_free:
    free(var1);
out:
    return retval;
}
如果考虑不带gotos 的等效项:
int function(const char * param)
{
    int retval = 1;
    char * var1 = fcn_that_returns_dynamically_allocated_string(param);
    if( var1 != NULL ){
       if( isValid(var1) ){
            retval = some_function(var1);
       } else {
          if( isGood(var1) ){
               retval = 0;
          }
       }
       free(var1);
    } else {
       retval = 0;
    }
    return retval;
}
对我而言,在第一种情况下,很明显,如果第一个函数返回NULL,则我们不在这里,而在返回0。在第二种情况下,我必须向下滚动才能看到if包含整个函数。授予第一个在样式上向我指示此名称(名称“ out”),第二个在语法上进行指示。第一个更加明显。
另外,我非常喜欢free()在函数末尾使用语句。部分原因是,根据我的经验,free()函数中间的语句很难闻,并向我表明我应该创建一个子例程。在这种情况下,我var1在函数中创建了函数,但无法free()在子例程中创建它,但这就是为什么goto out_freegoto out样式如此实用的原因。
我认为程序员必须长大,认为这goto是邪恶的。然后,当他们足够成熟时,他们应该浏览Linux源代码并阅读linux样式指南。
我应该补充一点,我非常一致地使用这种样式,每个函数都有一个int retval,一个out_free标签和一个out标签。由于风格上的一致性,提高了可读性。
奖励:打破并继续
假设您有一个while循环
char *var1, *var2;
char line[MAX_LINE_LENGTH];
while( sscanf(line,... ){
    var1 = functionA(line,count);
    var2 = functionB(line,count);
    if( functionC(var1, var2){
         count++
         continue;
    }
    ...
    a bunch of statements
    ...
    count++;
    free(var1);
    free(var2);
}
这段代码还有其他问题,但是一件事是continue语句。我想重写整个内容,但是我的任务是以较小的方式对其进行修改。以一种令我满意的方式来重构它可能需要几天的时间,但实际的更改大约需要花半天的时间。问题在于,即使continue我们仍然需要自由var1和自由var2。我必须添加一个var3,这让我想不得不镜像free()语句。
当时我是一个相对较新的实习生,但是前一段时间我一直在看linux源代码,所以我问我的主管我是否可以使用goto语句。他说可以,而我做到了:
char *var1, *var2;
char line[MAX_LINE_LENGTH];
while( sscanf(line,... ){
    var1 = functionA(line,count);
    var2 = functionB(line,count);
    var3 = newFunction(line,count);
    if( functionC(var1, var2){
         goto next;
    }
    ...
    a bunch of statements
    ...
next:
    count++;
    free(var1);
    free(var2);
}
我认为继续充其量是可以的,但对我而言,它们就像带有隐形标签的goto。休息时间也一样。我仍然希望继续或中断,除非像这里的情况那样,它迫使您在多个位置镜像修改。
我还要补充一点,goto next;和的使用next:对我来说并不令人满意。它们仅比镜像free()的和count++语句更好。  
goto几乎总是错误的,但是必须知道何时可以使用它们。  
我没有讨论的一件事是错误处理,该问题已被其他答案所涵盖。 
性能
可以看看strtok()的实现http://opensource.apple.com//source/Libc/Libc-167/string.subproj/strtok.c
#include <stddef.h>
#include <string.h>
char *
strtok(s, delim)
    register char *s;
    register const char *delim;
{
    register char *spanp;
    register int c, sc;
    char *tok;
    static char *last;
    if (s == NULL && (s = last) == NULL)
        return (NULL);
    /*
     * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
     */
cont:
    c = *s++;
    for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
        if (c == sc)
            goto cont;
    }
    if (c == 0) {       /* no non-delimiter characters */
        last = NULL;
        return (NULL);
    }
    tok = s - 1;
    /*
     * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
     * Note that delim must have one NUL; we stop if we see that, too.
     */
    for (;;) {
        c = *s++;
        spanp = (char *)delim;
        do {
            if ((sc = *spanp++) == c) {
                if (c == 0)
                    s = NULL;
                else
                    s[-1] = 0;
                last = s;
                return (tok);
            }
        } while (sc != 0);
    }
    /* NOTREACHED */
}
如果我错了,请指正我,但我相信cont:标签和goto cont;语句的存在是为了提高性能(它们肯定不会使代码更具可读性)。通过执行以下操作,可以将其替换为可读代码
while( isDelim(*s++,delim));
跳过定界符。但是为了尽可能快并避免不必要的函数调用,他们是这样做的。
我读了Dijkstra的论文,发现它很深奥。 
google“ dijkstra goto声明被认为是有害的”,因为我没有足够的声誉来发布两个以上的链接。
我已经看到它被引用为不使用goto的原因,并且阅读它对我对goto的使用没有任何改变。
附录:
在考虑所有有关持续和中断的问题时,我想出了一条整洁的规则。
- 如果在while循环中有一个continue,则while循环的主体应该是一个函数,而continue应该是一个return语句。 
 
- 如果在while循环中有一个break语句,则while循环本身应该是一个函数,而break应该成为return语句。 
 
- 如果两者都存在,则可能出了问题。
 
由于范围问题,这并不总是可能的,但是我发现这样做可以使我的代码推理变得容易得多。我注意到,只要while循环中断或继续,都会给我一种不好的感觉。