while terminar salir romper for ejemplos ejemplo como ciclo bucle c exception-handling language-agnostic goto

terminar - ¿Es alguna vez ventajoso usar ''goto'' en un lenguaje que admita bucles y funciones? Si es así, ¿por qué?



goto c++ ejemplos (24)

Si es así, ¿por qué?

C has no multi-level/labelled break, and not all control flows can be easily modelled with C''s iteration and decision primitives. gotos go a long way towards redressing these flaws.

Sometimes it''s clearer to use a flag variable of some kind to effect a kind of pseudo-multi-level break, but it''s not always superior to the goto (at least a goto allows one to easily determine where control goes to, unlike a flag variable), and sometimes you simply don''t want to pay the performance price of flags/other contortions to avoid the goto.

libavcodec is a performance-sensitive piece of code. Direct expression of the control flow is probably a priority, because it''ll tend to run better.

Durante mucho tiempo tuve la impresión de que nunca debería usarse goto si es posible. Mientras examinaba libavcodec (que está escrito en C) el otro día, noté usos múltiples de él. ¿Es alguna vez ventajoso usar goto en un lenguaje que admita bucles y funciones? Si es así, ¿por qué?


Bueno, hay una cosa que siempre es peor que la de goto''s ; uso extraño de otros operadores de flujo de programa para evitar un goto:

Ejemplos:

// 1 try{ ... throw NoErrorException; ... } catch (const NoErrorException& noe){ // This is the worst } // 2 do { ...break; ...break; } while (false); // 3 for(int i = 0;...) { bool restartOuter = false; for (int j = 0;...) { if (...) restartOuter = true; if (restartOuter) { i = -1; } } etc etc


Como goto hace que el razonamiento sobre el flujo de programas sea difícil 1 (también conocido como "código de spaghetti"), goto generalmente solo se utiliza para compensar características faltantes: el uso de goto puede ser aceptable, pero solo si el lenguaje no ofrece una estructura variante para obtener el mismo objetivo. Tome el ejemplo de Doubt:

La regla con goto que usamos es que goto está bien para saltar hacia adelante a un único punto de limpieza de salida en una función.

Esto es cierto, pero solo si el lenguaje no permite el manejo estructurado de excepciones con código de limpieza (como RAII o finally ), que hace el mismo trabajo mejor (ya que está especialmente diseñado para hacerlo), o cuando hay una buena razón no emplear el manejo estructurado de excepciones (pero nunca tendrás este caso excepto en un nivel muy bajo).

En la mayoría de los demás lenguajes, el único uso aceptable de goto es salir de los bucles anidados. E incluso allí, casi siempre es mejor levantar el bucle externo en un método propio y utilizar el return en return lugar.

Aparte de eso, goto es una señal de que no se ha pensado lo suficiente en la pieza de código en particular.

1 Los lenguajes modernos que soportan goto implementan algunas restricciones (p. Ej., goto puede no saltar dentro o fuera de las funciones) pero el problema fundamentalmente sigue siendo el mismo.

Por cierto, lo mismo es cierto para otras características del lenguaje, especialmente excepciones. Y, por lo general, existen reglas estrictas para usar estas funciones solo cuando se indique, como la regla de no usar excepciones para controlar el flujo de programas no excepcionales.


Eche un vistazo a Cuándo usar Ir a programar en C :

Aunque el uso de goto es casi siempre una mala práctica de programación (seguramente se puede encontrar una mejor manera de hacer XYZ), hay momentos en los que realmente no es una mala elección. Algunos incluso podrían argumentar que, cuando es útil, es la mejor opción.

La mayor parte de lo que tengo que decir sobre goto realmente solo se aplica a C. Si estás usando C ++, no hay razón para usar goto en lugar de excepciones. En C, sin embargo, no tiene el poder de un mecanismo de manejo de excepciones, por lo que si desea separar el manejo de errores del resto de la lógica de su programa, y ​​quiere evitar reescribir el código de limpieza varias veces a lo largo de su código, entonces goto puede ser una buena opción.

¿Que quiero decir? Es posible que tenga un código que se parece a esto:

int big_function() { /* do some work */ if([error]) { /* clean up*/ return [error]; } /* do some more work */ if([error]) { /* clean up*/ return [error]; } /* do some more work */ if([error]) { /* clean up*/ return [error]; } /* do some more work */ if([error]) { /* clean up*/ return [error]; } /* clean up*/ return [success]; }

Esto está bien hasta que se da cuenta de que necesita cambiar su código de limpieza. Luego tienes que pasar y hacer 4 cambios. Ahora, puede decidir que puede encapsular toda la limpieza en una sola función; Esa no es una mala idea. Pero significa que tendrá que tener cuidado con los punteros: si planea liberar un puntero en su función de limpieza, no hay forma de configurarlo para apuntar a NULL a menos que pase un puntero a un puntero. En muchos casos, no volverá a utilizar ese puntero de todos modos, por lo que puede no ser una preocupación importante. Por otro lado, si agrega un nuevo puntero, manejador de archivo u otra cosa que necesite limpieza, necesitará cambiar su función de limpieza nuevamente; y luego tendrá que cambiar los argumentos a esa función.

Al usar goto , será

int big_function() { int ret_val = [success]; /* do some work */ if([error]) { ret_val = [error]; goto end; } /* do some more work */ if([error]) { ret_val = [error]; goto end; } /* do some more work */ if([error]) { ret_val = [error]; goto end; } /* do some more work */ if([error]) { ret_val = [error]; goto end; } end: /* clean up*/ return ret_val; }

El beneficio aquí es que su código siguiente tiene acceso a todo lo que necesitará para realizar la limpieza, y ha logrado reducir considerablemente el número de puntos de cambio. Otro beneficio es que ha pasado de tener múltiples puntos de salida para su función a solo uno; no hay posibilidad de que regrese accidentalmente de la función sin limpiar.

Además, dado que goto solo se usa para saltar a un único punto, no es como si estuvieras creando una gran cantidad de código de spaghetti saltando hacia adelante y hacia atrás en un intento de simular llamadas de función. Por el contrario, goto en realidad ayuda a escribir un código más estructurado.

En una palabra, goto siempre debe usarse con moderación y como último recurso, pero hay un tiempo y un lugar para ello. La pregunta no debe ser "¿tiene que usarla?" Sino "¿es la mejor opción?" Para usarla.


En la sentencia de switch C # , no permita la caída . Entonces goto se usa para transferir el control a una etiqueta de caja de interruptor específica o la etiqueta default .

Por ejemplo:

switch(value) { case 0: Console.Writeln("In case 0"); goto case 1; case 1: Console.Writeln("In case 1"); goto case 2; case 2: Console.Writeln("In case 2"); goto default; default: Console.Writeln("In default"); break; }

Editar: hay una excepción en la regla "sin caída". Fall-through está permitido si un enunciado de caso no tiene código.


Hay algunas razones para usar la declaración "goto" de la que soy consciente (algunos ya han hablado de esto):

Limpiamente saliendo de una función

A menudo en una función, puede asignar recursos y necesita salir en múltiples lugares. Los programadores pueden simplificar su código poniendo el código de limpieza de recursos al final de la función, y todos los "puntos de salida" de la función irían a la etiqueta de limpieza. De esta manera, no tiene que escribir el código de limpieza en cada "punto de salida" de la función.

Saliendo de bucles anidados

Si está en un bucle anidado y necesita salir de todos los bucles, un goto puede hacer esto mucho más limpio y más simple que las declaraciones de interrupción y las verificaciones de if.

Mejoras de rendimiento de bajo nivel

Esto solo es válido en el código perf-critical, pero las declaraciones goto se ejecutan muy rápido y pueden darle un impulso cuando se mueve a través de una función. Sin embargo, este es un arma de doble filo, porque un compilador generalmente no puede optimizar el código que contiene gotos.

Tenga en cuenta que en todos estos ejemplos, los gotos están restringidos al alcance de una sola función.


He escrito más de unas pocas líneas de lenguaje ensamblador a lo largo de los años. En definitiva, cada lenguaje de alto nivel se compila en gotos. De acuerdo, llámalos "ramas" o "saltos" o lo que sea, pero son buenos. ¿Alguien puede escribir ensamblador goto-less?

Ahora bien, puedes señalar a un programador de Fortran, C o BASIC que correr disturbios con gotos es una receta para spaghetti bolognaise. La respuesta, sin embargo, no es evitarlos, sino usarlos con cuidado.

Un cuchillo puede usarse para preparar comida, liberar a alguien o matar a alguien. ¿Lo hacemos sin cuchillos por miedo a este último? Del mismo modo, el goto: utilizado sin cuidado obstaculiza, utilizado cuidadosamente ayuda.


La regla con goto que usamos es que goto está bien para saltar hacia adelante a un único punto de limpieza de salida en una función. En funciones realmente complejas relajamos esa regla para permitir otros saltos hacia adelante. En ambos casos, estamos evitando las declaraciones anidadas que a menudo ocurren con la comprobación de código de error, lo que ayuda a la legibilidad y el mantenimiento.


Me parece gracioso que algunas personas lleguen a dar una lista de casos en que goto sea aceptable, diciendo que todos los otros usos son inaceptables. ¿De verdad crees que conoces todos los casos en que goto es la mejor opción para expresar un algoritmo?

Para ilustrar, le daré un ejemplo que nadie aquí ha mostrado aún:

Hoy estaba escribiendo código para insertar un elemento en una tabla hash. La tabla hash es un caché de cálculos previos que pueden sobrescribirse a voluntad (afectando el rendimiento pero no la corrección).

Cada cubo de la tabla hash tiene 4 ranuras, y tengo un montón de criterios para decidir qué elemento sobrescribir cuando un depósito está lleno. En este momento esto significa hacer hasta tres pases a través de un cubo, como este:

// Overwrite an element with same hash key if it exists for (add_index=0; add_index < ELEMENTS_PER_BUCKET; add_index++) if (slot_p[add_index].hash_key == hash_key) goto add; // Otherwise, find first empty element for (add_index=0; add_index < ELEMENTS_PER_BUCKET; add_index++) if ((slot_p[add_index].type == TT_ELEMENT_EMPTY) goto add; // Additional passes go here... add: // element is written to the hash table here

Ahora, si no usara goto, ¿cómo se vería este código?

Algo como esto:

// Overwrite an element with same hash key if it exists for (add_index=0; add_index < ELEMENTS_PER_BUCKET; add_index++) if (slot_p[add_index].hash_key == hash_key) break; if (add_index >= ELEMENTS_PER_BUCKET) { // Otherwise, find first empty element for (add_index=0; add_index < ELEMENTS_PER_BUCKET; add_index++) if ((slot_p[add_index].type == TT_ELEMENT_EMPTY) break; if (add_index >= ELEMENTS_PER_BUCKET) // Additional passes go here (nested further)... }

// el elemento se escribe en la tabla hash aquí

Se vería cada vez peor si se agregan más pases, mientras que la versión con goto mantiene el mismo nivel de indentación en todo momento y evita el uso de declaraciones espurias, cuyo resultado está implícito en la ejecución del ciclo anterior.

Así que hay otro caso en que goto hace que el código sea más limpio y más fácil de escribir y entender ... Estoy seguro de que hay muchos más, así que no pretendas saber todos los casos en los que goto es útil, e ignora los que no pudiste No pienses en


Obedecer las mejores prácticas a ciegas no es una mejor práctica. La idea de evitar las declaraciones goto como la principal forma de control de flujo es evitar producir código de espagueti ilegible. Si se usan con moderación en los lugares correctos, a veces pueden ser la manera más simple y clara de expresar una idea. Walter Bright, el creador del compilador Zortech C ++ y el lenguaje de programación D, los usa con frecuencia, pero con criterio. Incluso con las declaraciones goto , su código todavía es perfectamente legible.

En pocas goto : evitar goto a goto para evitar goto tiene sentido. Lo que realmente quieres evitar es producir código ilegible. Si su código " goto -laden" es legible, entonces no tiene nada de malo.


Todos los que son anti- goto , directa o indirectamente, el artículo GoTo Considered Harmful de Edsger Dijkstra para corroborar su posición. Lástima que el artículo de Dijkstra prácticamente no tiene nada que ver con la forma en que se usan las declaraciones de goto en la actualidad y, por lo tanto, lo que dice el artículo tiene poca o ninguna aplicabilidad a la escena de programación moderna. El meme sin coordenadas ahora abarca una religión, hasta sus escrituras dictadas desde lo alto, sus sumos sacerdotes y el rechazo (o peor) de los herejes percibidos.

Pongamos el documento de Dijkstra en contexto para arrojar un poco de luz sobre el tema.

Cuando Dijkstra escribió su artículo, los lenguajes populares de la época eran procedimientos no estructurados como BASIC, FORTRAN (los dialectos anteriores) y varios lenguajes de ensamblaje. Era bastante común que las personas que usaban los lenguajes de alto nivel saltaran sobre su base de código en hilos de ejecución retorcidos y retorcidos que daban lugar al término "código de spaghetti". Puedes ver esto yendo al clásico juego Trek escrito por Mike Mayfield e intentando descubrir cómo funcionan las cosas. Tómese unos minutos para analizarlo.

ESTE es "el uso desenfrenado de la declaración ir a" que Dijkstra estaba criticando en su periódico en 1968. ESTE es el entorno en el que vivió que lo llevó a escribir ese artículo. La capacidad de saltar a cualquier lugar que desee en su código en cualquier punto que le gustara era lo que criticaba y exigía que se detuviera. Comparando eso con los poderes anémicos de goto en C u otros idiomas más modernos es simplemente risible.

Ya puedo escuchar los cánticos elevados de los miembros del culto cuando se enfrentan al hereje. "Pero", van a cantar, "puede hacer que el código sea muy difícil de leer con goto en C." ¿Oh si? Puede hacer que el código sea muy difícil de leer sin goto también. Como éste:

#define _ -F<00||--F-OO--; int F=00,OO=00;main(){F_OO();printf("%1.3f/n",4.*-F/OO/OO);}F_OO() { _-_-_-_ _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_ _-_-_-_ }

No se goto nada, así que debe ser fácil de leer, ¿verdad? O qué tal este:

a[900]; b;c;d=1 ;e=1;f; g;h;O; main(k, l)char* *l;{g= atoi(* ++l); for(k= 0;k*k< g;b=k ++>>1) ;for(h= 0;h*h<= g;++h); --h;c=( (h+=g>h *(h+1)) -1)>>1; while(d <=g){ ++O;for (f=0;f< O&&d<=g ;++f)a[ b<<5|c] =d++,b+= e;for( f=0;f<O &&d<=g; ++f)a[b <<5|c]= d++,c+= e;e= -e ;}for(c =0;c<h; ++c){ for(b=0 ;b<k;++ b){if(b <k/2)a[ b<<5|c] ^=a[(k -(b+1)) <<5|c]^= a[b<<5 |c]^=a[ (k-(b+1 ))<<5|c] ;printf( a[b<<5|c ]?"%-4d" :" " ,a[b<<5 |c]);} putchar( ''/n'');}} /*Mike Laman*/

No hay goto allí tampoco. Por lo tanto, debe ser legible.

¿Cuál es mi punto con estos ejemplos? No son las características del lenguaje las que crean un código ilegible e inmanejable. No es la sintaxis lo que lo hace. Son malos programadores que causan esto. Y los programadores malos, como puede ver en el artículo anterior, pueden hacer que cualquier característica del idioma sea ilegible e inutilizable. Como los bucles para allá arriba. (Puedes verlos, ¿verdad?)

Ahora, para ser justos, algunos constructos de lenguaje son más fáciles de abusar que otros. Sin embargo, si eres un programador de C, analizaría mucho más de cerca el 50% de los usos de #define mucho antes de ir a una cruzada contra goto !

Entonces, para aquellos que se han molestado en leer hasta aquí, hay varios puntos clave a tener en cuenta.

  1. El artículo de Dijkstra sobre declaraciones goto fue escrito para un entorno de programación donde goto era mucho más dañino que en la mayoría de los lenguajes modernos que no son ensambladores.
  2. Descartar automáticamente todos los usos de goto es casi tan racional como decir "Intenté divertirme una vez pero no me gustó, así que ahora estoy en contra de eso".
  3. Existen usos legítimos de las declaraciones goto modernas (anémicas) en el código que no pueden ser reemplazadas adecuadamente por otras construcciones.
  4. Hay, por supuesto, usos ilegítimos de las mismas declaraciones.
  5. También hay usos ilegítimos de las declaraciones modernas de control, como la abominación de " godo ", donde un ciclo siempre falso se rompe con el uso de break en lugar de un goto . A menudo son peores que el uso juicioso de goto .

Tenga en cuenta cuando me está votando con un -1 tras otro que he usado goto en mi propio código (no ensamblador) precisamente 3 veces en los últimos 15-20 años.

Espero el torrente de gritos indignados y -1 votos con la respiración contenida.


Una de las razones por las que goto es malo, además del estilo de codificación es que puede usarlo para crear bucles superpuestos pero no anidados :

loop1: a loop2: b if(cond1) goto loop1 c if(cond2) goto loop2

Esto crearía una estructura de flujo de control extraña, pero posiblemente legal, donde una secuencia como (a, b, c, b, a, b, a, b, ...) es posible, lo que hace infelices a los piratas informáticos. Aparentemente hay una cantidad de astutos trucos de optimización que dependen de que este tipo de estructura no ocurra. (Debería consultar mi copia del libro de dragones ...) El resultado de esto podría ser (usando algunos compiladores) que otras optimizaciones no se hagan para el código que contiene goto s.

Puede ser útil si lo sabe solo, "oh, por cierto", persuade al compilador a emitir un código más rápido. Personalmente, preferiría tratar de explicarle al compilador sobre lo que es probable y lo que no, usando un truco como goto, pero podría decirse que también podría probarlo antes de hackear el ensamblador.


1) The most common use of goto that I know of is emulating exception handling in languages that don''t offer it, namely in C. (The code given by Nuclear above is just that.) Look at the Linux source code and you''ll see a bazillion gotos used that way; there were about 100,000 gotos in Linux code according to a quick survey conducted in 2013: http://blog.regehr.org/archives/894 . Goto usage is even mentioned in the Linux coding style guide: https://www.kernel.org/doc/Documentation/CodingStyle . Just like object-oriented programming is emulated using structs populated with function pointers, goto has its place in C programming. So who is right: Dijkstra or Linus (and all Linux kernel coders)? It''s theory vs. practice basically.

There is however the usual gotcha for not having compiler-level support and checks for common constructs/patterns: it''s easier to use them wrong and introduce bugs without compile-time checks. Windows and Visual C++ but in C mode offer exception handling via SEH/VEH for this very reason: exceptions are useful even outside OOP languages, ie in a procedural language. But the compiler can''t always save your bacon, even if it offers syntactic support for exceptions in the language. Consider as example of the latter case the famous Apple SSL "goto fail" bug, which just duplicated one goto with disastrous consequences ( https://www.imperialviolet.org/2014/02/22/applebug.html ):

if (something()) goto fail; goto fail; // copypasta bug printf("Never reached/n"); fail: // control jumps here

You can have exactly the same bug using compiler-supported exceptions, eg in C++:

struct Fail {}; try { if (something()) throw Fail(); throw Fail(); // copypasta bug printf("Never reached/n"); } catch (Fail&) { // control jumps here }

But both variants of the bug can be avoided if the compiler analyzes and warns you about unreachable code. For example compiling with Visual C++ at the /W4 warning level finds the bug in both cases. Java for instance forbids unreachable code (where it can find it!) for a pretty good reason: it''s likely to be a bug in the average Joe''s code. As long as the goto construct doesn''t allow targets that the compiler can''t easily figure out, like gotos to computed addresses(**), it''s not any harder for the compiler to find unreachable code inside a function with gotos than using Dijkstra-approved code.

(**) Footnote: Gotos to computed line numbers are possible in some versions of Basic, eg GOTO 10*x where x is a variable. Rather confusingly, in Fortran "computed goto" refers to a construct that is equivalent to a switch statement in C. Standard C doesn''t allow computed gotos in the language, but only gotos to statically/syntactically declared labels. GNU C however has an extension to get the address of a label (the unary, prefix && operator) and also allows a goto to a variable of type void*. See https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html for more on this obscure sub-topic. The rest of this post ins''t concerned with that obscure GNU C feature.

Standard C (ie not computed) gotos are not usually the reason why unreachable code can''t be found at compile time. The usual reason is logic code like the following. Dado

int computation1() { return 1; } int computation2() { return computation1(); }

It''s just as hard for a compiler to find unreachable code in any of the following 3 constructs:

void tough1() { if (computation1() != computation2()) printf("Unreachable/n"); } void tough2() { if (computation1() == computation2()) goto out; printf("Unreachable/n"); out:; } struct Out{}; void tough3() { try { if (computation1() == computation2()) throw Out(); printf("Unreachable/n"); } catch (Out&) { } }

(Excuse my brace-related coding style, but I tried to keep the examples as compact as possible.)

Visual C++ /W4 (even with /Ox) fails to find unreachable code in any of these, and as you probably know the problem of finding unreachable code is undecidable in general. (If you don''t believe me about that: https://www.cl.cam.ac.uk/teaching/2006/OptComp/slides/lecture02.pdf )

As a related issue, the C goto can be used to emulate exceptions only inside the body of a function. The standard C library offers a setjmp() and longjmp() pair of functions for emulating non-local exits/exceptions, but those have some serious drawbacks compared to what other languages offer. The Wikipedia article http://en.wikipedia.org/wiki/Setjmp.h explains fairly well this latter issue. This function pair also works on Windows ( http://msdn.microsoft.com/en-us/library/yz2ez4as.aspx ), but hardly anyone uses them there because SEH/VEH is superior. Even on Unix, I think setjmp and longjmp are very seldom used.

2) I think the second most common use of goto in C is implementing multi-level break or multi-level continue, which is also a fairly uncontroversial use case. Recall that Java doesn''t allow goto label, but allows break label or continue label. According to http://www.oracle.com/technetwork/java/simple-142616.html , this is actually the most common use case of gotos in C (90% they say), but in my subjective experience, system code tends to use gotos for error handling more often. Perhaps in scientific code or where the OS offers exception handling (Windows) then multi-level exits are the dominant use case. They don''t really give any details as to the context of their survey.

Edited to add: it turns out these two use patterns are found in the C book of Kernighan and Ritchie, around page 60 (depending on edition). Another thing of note is that both use cases involve only forward gotos. And it turns out that MISRA C 2012 edition (unlike the 2004 edition) now permits gotos, as long as they are only forward ones.


#ifdef TONGUE_IN_CHEEK

Perl tiene un goto que te permite implementar llamadas de cola de pobre. :-PAG

sub factorial { my ($n, $acc) = (@_, 1); return $acc if $n < 1; @_ = ($n - 1, $acc * $n); goto &factorial; }

#endif

De acuerdo, entonces eso no tiene nada que ver con el goto de C. Más en serio, estoy de acuerdo con los otros comentarios sobre el uso de goto para las limpiezas, o para implementar el dispositivo de Duff , o similares. Se trata de usar, no de abusar.

(El mismo comentario puede aplicarse a longjmp , excepciones, call/cc , y similares --- tienen usos legítimos, pero se pueden abusar fácilmente. Por ejemplo, lanzando una excepción puramente para escapar de una estructura de control profundamente anidada, bajo completamente circunstancias no excepcionales.)


Edsger Dijkstra, a computer scientist that had major contributions on the field, was also famous for criticizing the use of GoTo. There''s a short article about his argument on Wikipedia .


I find the do{} while(false) usage utterly revolting. It is conceivable might convince me it is necessary in some odd case, but never that it is clean sensible code.

If you must do some such loop, why not make the dependence on the flag variable explicit?

for (stepfailed=0 ; ! stepfailed ; /*empty*/)


I use goto in the following case: when needed to return from funcions at different places, and before return some uninitialization needs to be done:

non-goto version:

int doSomething (struct my_complicated_stuff *ctx) { db_conn *conn; RSA *key; char *temp_data; conn = db_connect(); if (ctx->smth->needs_alloc) { temp_data=malloc(ctx->some_size); if (!temp_data) { db_disconnect(conn); return -1; } } ... if (!ctx->smth->needs_to_be_processed) { free(temp_data); db_disconnect(conn); return -2; } pthread_mutex_lock(ctx->mutex); if (ctx->some_other_thing->error) { pthread_mutex_unlock(ctx->mutex); free(temp_data); db_disconnect(conn); return -3; } ... key=rsa_load_key(....); ... if (ctx->something_else->error) { rsa_free(key); pthread_mutex_unlock(ctx->mutex); free(temp_data); db_disconnect(conn); return -4; } if (ctx->something_else->additional_check) { rsa_free(key); pthread_mutex_unlock(ctx->mutex); free(temp_data); db_disconnect(conn); return -5; } pthread_mutex_unlock(ctx->mutex); free(temp_data); db_disconnect(conn); return 0; }

goto version:

int doSomething_goto (struct my_complicated_stuff *ctx) { int ret=0; db_conn *conn; RSA *key; char *temp_data; conn = db_connect(); if (ctx->smth->needs_alloc) { temp_data=malloc(ctx->some_size); if (!temp_data) { ret=-1; goto exit_db; } } ... if (!ctx->smth->needs_to_be_processed) { ret=-2; goto exit_freetmp; } pthread_mutex_lock(ctx->mutex); if (ctx->some_other_thing->error) { ret=-3; goto exit; } ... key=rsa_load_key(....); ... if (ctx->something_else->error) { ret=-4; goto exit_freekey; } if (ctx->something_else->additional_check) { ret=-5; goto exit_freekey; } exit_freekey: rsa_free(key); exit: pthread_mutex_unlock(ctx->mutex); exit_freetmp: free(temp_data); exit_db: db_disconnect(conn); return ret; }

The second version makes it easier, when you need to change something in the deallocation statements (each is used once in the code), and reduces the chance to skip any of them, when adding a new branch. Moving them in a function will not help here, because the deallocation can be done at different "levels".


In Perl, use of a label to "goto" from a loop - using a "last" statement, which is similar to break.

This allows better control over nested loops.

The traditional goto label is supported too, but I''m not sure there are too many instances where this is the only way to achieve what you want - subroutines and loops should suffice for most cases.


In a Perl module, you occasionally want to create subroutines or closures on the fly. The thing is, that once you have created the subroutine, how do you get to it. You could just call it, but then if the subroutine uses caller() it won''t be as helpful as it could be. That is where the goto &subroutine variation can be helpful.

Here is a quick example:

sub AUTOLOAD{ my($self) = @_; my $name = $AUTOLOAD; $name =~ s/.*:://; *{$name} = my($sub) = sub{ # the body of the closure } goto $sub; # nothing after the goto will ever be executed. }

You can also use this form of goto to provide a rudimentary form of tail-call optimization.

sub factorial($){ my($n,$tally) = (@_,1); return $tally if $n <= 1; $tally *= $n--; @_ = ($n,$tally); goto &factorial; }

( In Perl 5 version 16 that would be better written as goto __SUB__; )

There is a module that will import a tail modifier and one that will import recur if you don''t like using this form of goto .

use Sub::Call::Tail; sub AUTOLOAD { ... tail &$sub( @_ ); } use Sub::Call::Recur; sub factorial($){ my($n,$tally) = (@_,1); return $tally if $n <= 1; recur( $n-1, $tally * $n ); }

Most of the other reasons to use goto are better done with other keywords.

Like redo ing a bit of code:

LABEL: ; ... goto LABEL if $x;

{ ... redo if $x; }

Or going to the last of a bit of code from multiple places:

goto LABEL if $x; ... goto LABEL if $y; ... LABEL: ;

{ last if $x; ... last if $y ... }


Just as well no one ever implemented the "COME FROM" statement....


Some say there is no reason for goto in C++. Some say that in 99% cases there are better alternatives. To be concrete, here''s an example where goto leads to a nice code, something like enhanced do-while loop:

int i; again: std::cout << "insert number: "; std::cin >> i; if(std::cin.fail()) { std::cin.clear(); std::cin.ignore(1000,''/n''); goto again; } std::cout << "your number is " << i;

Compare it to goto-free code:

int i; bool loop; do { loop = false; std::cout << "insert number: "; std::cin >> i; if(std::cin.fail()) { std::cin.clear(); std::cin.ignore(1000,''/n''); loop = true; } } while(loop); std::cout << "your number is " << i;

I see these differences:

  • nested {} block is needed (albeit do {...} while looks more familiar)
  • extra loop variable is needed, used in four places
  • it takes longer time to read and understand the work with the loop
  • the loop does not hold any data, it just controls the flow of the execution, which is less comprehensible than simple label

The point is that goto can be easily misused, but goto itself is not to blame. Note that label has function scope in C++, so it does not pollute global scope like in pure assembly, in which overlapping loops has its place and are very common - like in the following code for 8051, where 7segment display is connected to P1. The program loops lightning segment around:

; P1 states loops ; 11111110 <- ; 11111101 | ; 11111011 | ; 11110111 | ; 11101111 | ; 11011111 | ; |_________| again: MOV P1,#11111110b ACALL delay loop: MOV A,P1 RL A MOV P1,A ACALL delay JNB P1.5, again SJMP loop


The GOTO can be used, of course, but there is one more important thing than the code style, or if the code is or not readable that you must have in mind when you use it: the code inside may not be as robust as you think .

For instance, look at the following two code snippets:

If A <> 0 Then A = 0 EndIf Write("Value of A:" + A)

An equivalent code with GOTO

If A == 0 Then GOTO FINAL EndIf A = 0 FINAL: Write("Value of A:" + A)

The first thing we think is that the result of both bits of code will be that "Value of A: 0" (we suppose an execution without parallelism, of course)

That''s not correct: in the first sample, A will always be 0, but in the second sample (with the GOTO statement) A might not be 0. Why?

The reason is because from another point of the program I can insert a GOTO FINAL without controlling the value of A.

This example is very obvious, but as programs get more complicated, the difficulty of seeing those kind of things increases.

Related material can be found into the famous article from Mr. Dijkstra "A case against the GO TO statement"


The most thoughtful and thorough discussion of goto statements, their legitimate uses, and alternative constructs that can be used in place of "virtuous goto statements" but can be abused as easily as goto statements, is Donald Knuth''s article " Structured Programming with goto Statements ", in the December 1974 Computing Surveys (volume 6, no. 4. pp. 261 - 301).

Not surprisingly, some aspects of this 39-year old paper are dated: Orders-of-magnitude increases in processing power make some of Knuth''s performance improvements unnoticeable for moderately sized problems, and new programming-language constructs have been invented since then. (For example, try-catch blocks subsume Zahn''s Construct, although they are rarely used in that way.) But Knuth covers all sides of the argument, and should be required reading before anyone rehashes the issue yet again.


The problem with ''goto'' and the most important argument of the ''goto-less programming'' movement is, that if you use it too frequently your code, although it might behave correctly, becomes unreadable, unmaintainable, unreviewable etc. In 99.99% of the cases ''goto'' leads to spaghetti code. Personally, I cannot think of any good reason as to why I would use ''goto''.