GOTO

GOTO

GOTO o GO TO (ir a en inglés) es una instrucción muy común en los lenguajes de programación con el objetivo de controlar el flujo del programa. El efecto de su versión más simple es transferir sin condiciones la ejecución del programa a la etiqueta o número de línea especificada. Es una de las operaciones más primitivas para traspasar el control de una parte del programa a otra; tal es así que muchos compiladores traducen algunas instrucciones de control como GOTO.

La instrucción se puede encontrar en muchos lenguajes; uno de los primeros lenguajes de alto nivel que lo incluyeron fue el FORTRAN, desarrollado en 1954. También se encuentra en: Algol, COBOL, SNOBOL, BASIC, Lisp, C,C#, C++, Pascal y Perl entre otros, especialmente el lenguaje ensamblador. En este último se lo puede encontrar como BRA (de branch: ramificar en inglés), JMP o JUMP (saltar o salto en inglés) y es, generalmente, el único modo de organizar el flujo del programa.

Existe incluso en lenguajes usados para la enseñanza de programación estructurada, como Pascal. Sin embargo, no está en todos los lenguajes de programación, en algunos (como Java) es una palabra reservada y en el paródico lenguaje INTERCAL se utiliza COME FROM (venir de en inglés).

Se pueden encontrar también variaciones de la instrucción GOTO. En BASIC, la instrucción ON GOTO puede seleccionar de una lista de diferentes puntos del programa a los que saltar. Podría ser interpretado como un antecesor de la instrucción switch/case. También, en FORTRAN y algunas versiones de BASIC la línea a la que saltar podía ser indicada mediante una expresión aritmética. Esto último era evitado ya que el código se hacía aún más ilegible teniendo en cuenta la necesidad de hacer los cálculos de la expresión de control para saber el destino del flujo del programa.

Contenido

Controversia sobre el uso de GOTO

A diferencia de la llamada a una función, no se requiere ningún tipo de preparación o estructura de código para utilizar un GOTO. Como resultado, es más sencillo obtener código inconsistente, incompleto o complicado de mantener. Justamente por ello en los años 60 y 70, cuando surgió la programación estructurada, la comunidad informática se expresó a favor de otras instrucciones de control (if ó bucles for y do/while) en lugar de GOTO.

Tal creencia está tan arraigada que el GOTO es muy criticado por los dedicados a la enseñanza de la programación, que lo suelen desaconsejar. Por el otro lado, algunos que si bien admiten el uso de un GOTO como una práctica desaconsejable, reconocen que éste es la mejor opción para algunas pocas tareas puntuales en algunos lenguajes de programación (manejo de excepciones por ejemplo). Además, por lo general se programan macros o equivalentes para evitar la utilización de GOTO.

Una crítica famosa a la instrucción en cuestión es una carta redactada por Edsger Dijkstra llamada "Go To Statement Considered Harmful" (Instrucción Go To Considerada Dañina). En ella Dijkstra argumenta que el uso irrestricto de GOTO debería ser prohibido en lenguajes de alto nivel ya que dificultan el análisis y la verificación de la corrección de los programas (especialmente aquellos que contienen ciclos). Por el otro lado, Donald Knuth en su libro "Structured Programming with goto Statements" (Programación estructurada con instrucciones Goto), tiene en cuenta ciertas situaciones en las que se utilizaría GOTO. Por lo general, se trata de situaciones en las que una estructura de programación en particular no está disponible y GOTO puede simularla eficientemente.

Interacción de GOTO dentro de otras estructuras de control

La sentencia GOTO, no sólo puede aparecer a lo largo del listado de instrucciones de un programa, sino que incluso puede enviar el flujo dentro de una estructura de control o fuera de la misma.

Es patente, la complejidad de entender un código cuyas estructuras de control lo estuvieran también cruzadas por sentencias GOTO. Si bien el uso de GOTO puede hacer posible situaciones de las que un lenguaje carece, el uso indiscriminado de éstas harían a un código muy difícil de entender y mantener.

Esto deriva en circunstancias especiales que se consideran a continuación:

GOTO envía del flujo fuera de una estructura de control

De modo general GOTO tiene otro enemigo, y es que cuando opera dentro de otra estructura de control que guarda punteros en la pila, si hay una sentencia GOTO que sale de la estructura de control, fuerza a que se vacíe la pila con los punteros de retorno que mantenía la estructura. Esto requiere un chequeo constante de la sentencia GOTO en busca de si aparece o no dentro de una estructura de control (Véase la sección donde se compara GOTO con otras estructuras de control, más adelante en este mismo artículo), para determinar si debe o no retirar de la pila un puntero al que aparentemente no se retornará ya. Una razón para salir de una estructura de control usando GOTO, es que dicha estructura no provea otro mecanismo de salida que llegar al final del bloque de sentencias que contiene la estructura, por lo que los diversos lenguajes han provisto una salida alternativa que solucione la operación que realiza GOTO en dichos casos y a su vez no requiere la verificación que se hacía precisa para cada GOTO, típicamente las sentencias de escape alternativas se han dado en llamar:

  • Para las estructura de control que no requieren punto de retorno. Exit flujo donde flujo es la estructura de control, tales como DO, FOR, etc...
  • Para la estructuras de control que requieren un punto de retorno, RETURN, tales como GOSUB, FUNCTION, etc..

Las sentencias EXIT, todavía están limitadas respecto de GOTO, pues EXIT siempre devuelve a la siguiente instrucción al final de la estructura de control.

Puede darse el caso en algunos lenguajes, que la ejecución de la sentencia GOTO no conlleve aparejado comprobar si salta fuera de una estructura de control y consecuentemente no elimine de la pila el puntero de retorno que se colocó al entrar a la rutina en dicho caso, a efectos del programa el control sigue dentro de dicha estructura y sigue esperando que alcance el final para volver al punto de retorno y vaciar la pila del valor de retorno, como esto ya no va a ocurrir, se está perdiendo espacio de pila con cada situación de este tipo. También podría darse el caso si algún lenguaje olvida aportar solución que al ir entregando desde la pila los sucsivos retornos, se apunte a un lugar diferente de la que el programador esperaba, por la cascada de entradas fue una y la cascada de salidas debiendo ser en orden inversa conserva una salida que nunca se va a producir, falsificando con ello todas las devoluciones anteriores a esa que se ha quedado perdida por la instrucción goto. Un modo en que algunos lenguajes solventan este problema es utilizando una pila exclusivamente local y eliminarla cuando se sale del procedimiento local, en dicho caso la dirección de retorno se guarda en una pila de ámbito mayor. Si hay punteros remanentes en la pila local no devueltos no producirán errores en cascada hacia atrás.

En situaciones así es difícil seguir la pista de saltos esperada respecto de la que el programador pretendiera hacer si no se comporta como él esperaba. También de este modo es posible hacer que el código se comporte de una forma que el lenguaje no tenía previsto en su diseño y aprovechar con ello una posible situación eficiente, para realizar determinadas tareas.

Adicionalmente para solventar los posibles problemas que el inadecuado uso de GOTO pueda originar, los lenguajes de alto nivel y que utilizan programación mediante bloques y módulos bien definidos y aislados, no permiten sobre GOTO más que operar dentro del bloque o módulo donde se aloja. Un caso típico son las modernas funciones FUNCTION, PROPERTY, etc... donde si bien un GOTO puede aparecer, no puede direccionar a un punto dentro de otra FUNCTION. No confundir este aislamiento con encapsulamiento, aunque la idea es la misma.

GOTO envía el flujo dentro de una estructura de control

Sucede de otra forma cuando un salto por GOTO nos introduce dentro de una estructura de control. Si hay instrucciones tras la etiqueta a la que se salta, éstas se ejecutan correctamente, pero al llegar a una instrucción del final, si la pila está vacía (cuando la estructura de control requiere un puntero de retorno), ocurre un error que según el lenguaje varía, y si la pila no está vacía salta a la dirección que señala el último puntero en la pila, puede considerarse un error si no era lo que perseguía el programador, toda vez que dicho puntero no fue almacenado por dicha estructura decontrol en la que se halla sino por la previa.

Esto sólo sucede en aquellas estructuras de control que guardan algún puntero de retorno en la pila, por ejemplo nunca ocurrirá un error dentro de una estructura IF...THEN, ni dentro de una estructura SELECT CASE (Switch), ni DO...LOOP ya que dichas estructuras al no tener al final un punto de retorno, no necesitan almacenar en la pila dicho punto de retorno.

Normalmente, es el caso que en los lenguajes, la ejecución de la sentencia GOTO no conlleva aparejado comprobar si salta dentro de una estructura de control, ya que en principio no debe generar errores aunque tenga un puntero de retorno siempre que este puntero esté localizado en la sentencia de salida en vez de en la pila.

Se detallan, comentados 3 casos comunes:

  • Caso de estructura de control donde el puntero de retorno se almacena en la sentencia final: este suele ser DO...LOOP, loop es equivalente a un GOTO DO. En una sección del artículo más adelante, se provee una implementación de la estructura de control DO...LOOP usando GOTO, que ayudará a entender este caso. En este caso por tanto saltar dentro de un estructura DO..LOOP no proporcionará un error si se llega a la sentencia final. (ver sección anterior). El puntero de retorno de esta estructura siempre apunta al principio de la estructura, es por esto que no necesita mantenerlo en la pila t resulta suficiente con dejarlo en la sentencia final.
  • Otro caso de estructura de control que el puntero de retorno se almacena en la sentecia final, pero que si da errores: un caso de este tipo suele ser FOR...NEXT. La estructura FOR se compone de 3 secciones operativas, en la primera se inicializan los valores del bucle, en la 2ª se produce el incremento de los valores que controlan el bucle y en la 3ª sección está el bloque de sentencias que se ha de repetir. Si una sentencia GOTO lleva el flujo dentro de un bucle FOR, cuando se alcanza la sentencia NEXT esta sabe localizar el retorno hacia la 2ª sección (en este sentido se comporta como DO...LOOP, (NEXT equivale a GOTO 2ª Seccion) pero al tratar de incrementar el bucle descubre que las variables que necesita el bucle no han sido inicializadas, por lo que produce un error de forma indirecta. Un bucle FOR utiliza 4 variables internamente para su propio control, una variable contador que es la que se irá incrementando, 3 variables o constantes que asigna el valor inicial,final y cantidad de incremento respectivamente.
  • Caso de estructura de control que el puntero de retorno se almacena en la pila: El caso de este tipo suele ser GOSUB. Cada vez que se ejecuta una sentencia GOSUB (FUNCTION, etc...) se guarda en la pila la dirección de origen, y cada vez que se ejecuta la sentencia RETURN, se salta a la última dirección contenida en la pila, es decir no existe un par asociado GOSUB...RETURN. Véase GOSUB para más detalles. Este caso es el más proclive a que ofrezca un comportamiento difícil de seguir.

GOTO envía el flujo desde dentro de una estructura de control a otro punto dentro

En cualquier caso puede haber innumerables sentencias GOTO dentro de una estructura de control, y recorrerla de forma arbitraria, sin que genere ningún error excepto que se alcance (ejecute su turno) una sentencia de retorno que requiera un puntero de retorno en la pila que no exista. como ya se comentó, si existen valores en la pila puede darse erores o no en base a si esa es la idea que perseguía el programador o no, ya que retornará el último puntero que contenga la pila.

Comparación entre GOTO y otras instrucciones de control del flujo

GOTO es incondicional, es decir ordena el salto de ejecución del programa a una dirección concreta. El salto se solicita porque se requiere que la ejecución continúe desde allí. La problemática de esto resulta en que no resulta evidente el orden de ejecución.

Como se podrá apreciar en las sucesivas comparaciones, GOTO puede implementar todas las estructuras de control, su controversia no se deduce de su versatilidad, si no de la enajenación de claridad en que resulta su uso. Las estructuras de control de lenguajes de alto nivel están realizadas usando GOTO (típicamente JMP, y sus variantes en ensamblador).

Comparación con GOSUB

Al igual que GOTO, GOSUB tampoco acepta (en la mayoría de lenguajes que se utiliza) un salto a una dirección que no sea una constante, es decir no acepta valores desde variables sino sólo desde constantes, lo que en cierto modo limita la casuística de errores en que pudiera derivar.

Una diferencia sustancial se establece con las instrucciones GOSUB (saltar a subrutina), la diferencia esencial es que gosub, tras saltar a la instrucción indicada, ejecuta un número determinado de instrucciones hasta que encuentra una instrucción RETURN, que le obliga volver a la siguiente instrucción que viene a continuación de la instrucción GOSUB. GOSUB, por tanto puede entenderse como utilizar 2 gotos, el que salta a la instrucción indicada, y el que retorna a la posición última que se guarda en la pila.

Es por esto que una instrucción GOTO, no guarda el origen de procedencia en la pila. GOSUB, debe necesariamente antes de proceder con el salto guardar en la pila la dirección desde la que salta, para que a su regreso el contador de programa incremente en una unidad.

GOSUB, por tanto delimita no sólo el inicio de un grupo de instrucciones sino que también queda claro su final. GOSUB requiere una instrucción de retorno, aunque nada impide colocar varias instrucciones de forma condicionada.

En consecuencia a estas consideraciones GOSUB ofrece un paso más allá el control del flujo que GOTO por sí solo no permite, no obstante, GOTO, puede emular a GOSUB, pues, puede allí donde hubiera un RETURN, remplazarse con un GOTO a la siguiente instrucción del GOTO de origen.

Implementación de GOSUB usando GOTO

Como puede deducrise en el ejemplo a continuación, ambos, son equivalentes, hacen lo mismo, la diferencia radica en que usando GOTO, el programador debe controlar todos los saltos (véase líneas GOTO x3), para regresar al punto de partida. GOSUB en cambio hace esto de forma automática, transparente para el programador, que se desentiende de que línea o qué dirección ha de tener el retorno, ya que este valor se guarda en la pila en el momento de procesar la sentencia GOSUB.

Nota previas para enteneder el ejemplo: instr representan cualquier instrucción. # representa un comentario en la línea a partir de ahí. El número que le sigue representa la continuidad en la posición de memoria, que sólo sirve al efecto de comprender mejor el ejemplo. Si este número va entre paréntesis indica una posición relativa respecto de éste.

ejemplo de rutina usando GOSUB...

 A = 5   # x-1
 instr # x
 instr # x+1
 GOSUB 400 # instr x+2
 instr # x+3 
 ...
 ...
 400:   # instr x+? 
 instr # (400)+1 
 instr # (400)+2
 Si A es= 2 luego
   instr # (400)+4
   RETURN
 En otro caso
   instr # (400)+7
   instr # (400)+8
 Fin casos
 RETURN

ejemplo de emulación de GOSUB usando GOTO...

 instr # x
 instr # x+1
 GOTO 400 # instr x+2
 X3:  # instr x+3 
 ...
 ...
 400:   # instr x+? 
 instr # (400)+1 
 instr # (400)+2
 Si A es= 2 luego
   instr # (400)+4
   GOTO x3
 En otro caso
   instr # (400)+7
   instr # (400)+8
 Fin casos
 GOTO x3


Comparación con IF...THEN...ELSE

Como ya se ha indicado, el salto de GOTO es incondicional, al llegar a ese punto se ejecuta y eso es todo, a un posible lector, no le queda claro cual es la razón de salto, sólo sabe a ciencia cierta que la ejecución continúa en el punto indicado y nada más, para comprender mejor que sucede necesita estudiar con detenimiiento las condiciones previas, lo que supone una ardua tarea, especialmente cuando se busca código optimizado para velocidad ya que entonces el mismo puede resulta más difícil de entender.

La principal diferencia entre GOTO y la sentencia IF...THEN..ELSE es que GOTO puede basar su salto en los condicionantes que se dan previamente, lo que obliga en la toma de decisiones a utilizar varias sentencias GOTO que lo hace aún más complejo de analizar.

La sentencia IF asocia el salto a un cúmulo de sucesos concretos (puede haber una o varias condiones cuya evaluación conjunta se evalúa como verdaero o falso, de modo que es posible y fácil entender que el salto se produce sólo si no se cumple la condición ejecutándose, si se cumple ´no se salta se continúa con las siguientes instrucciones y al final de las mismas salta hasta el final de todo el bloque que forman la sentencia y las instrucciones asociadas a sendas condiciones.

Para comprender correctamente como se produce esto es necesario distinguir la sentencia de salto condicional IF que es de alto nivel, con las instrucciones ensamblador de salto condicional (saltar si cero, saltar si no cero, etc...). Son estas últimas quienes determinan si el salto se produce dadas las condiciones.

Implementación de IF usando GOTO

Comparación con FOR...NEXT

Implementación de FOR usando GOTO

Comparación con DO...LOOP (WHILE)

Implementación de DO usando GOTO

Comparación con FUNCION

Implementación de FUNCION usando GOTO

Ejemplos

En Pascal, donde se deben declaran las etiquetas con la palabra reservada LABEL:

Program UsoGOTO (input, output);
uses crt; var salto:char; LABEL
Salto;
BEGIN
Writeln('Como estamos antes del GOTO esto saldrá en pantalla');
GOTO Salto;
Writeln('Esto no saldrá en pantalla');
Salto:
Writeln('Se efectuó una ruptura en el flujo debido a la sentencia GOTO')
END

En Lenguaje de programación C se declaran las etiquetas con dos puntos al final.

#include <stdio.h>
 
int main()
{
etiqueta: //La etiqueta
printf("Uso del GOTO");
goto etiqueta;
}

En Lenguaje de programación C# se declaran las etiquetas con dos puntos al final.

 
static void main()
{
etiqueta: //La etiqueta
goto etiqueta; //Ir a la etiqueta
}

En BASIC, las etiquetas se sentencian igual que en C, con dos puntos al final.

PRINT "Prueba de GOTO en QBASIC"
GOTO prueba
PRINT "Esto no se ve porque hemos saltado a la etiqueta llamada prueba"
prueba:
PRINT "GOTO realizado correctamente!"

En algunas variantes de BASIC, como por ejemplo Just BASIC o Liberty BASIC, se usa [ y ] para remarcar etiquetas:

 
PRINT "Prueba de GOTO en QBASIC"
GOTO [prueba]
PRINT "Esto no se ve porque hemos saltado a la etiqueta llamada prueba"
[prueba]
PRINT "GOTO realizado correctamente!"

En ensamblador se emplean instrucciones similares. En el caso de x86 la instrucción es jmp:

# Programa para GNU/Linux.
# Ensamblar con cc jmp.S -o jmp
# Muestra "Comenzando bucle" y seguidamente entra en un bucle
# mostrando "Hola, mundo" a cada iteración
    .section .rodata
    msg1:
        .string "Hola, mundo"
 
    msg2:
        .string "Comenzando bucle"
    .section .text
    .globl main
 
main:
    movl $msg2,(%esp)
    call puts
etiqueta:
    movl $msg,(%esp)
    call puts
    jmp etiqueta

Véase también


Wikimedia foundation. 2010.

Игры ⚽ Поможем написать курсовую

Mira otros diccionarios:

  • GOTO — (англ. go to  «перейти к»)  в некоторых языках программирования  оператор безусловного перехода (перехода к определённой точке программы, обозначенной номером строки либо меткой). В более широком смысле, под «GOTO»… …   Википедия

  • Goto — is a statement found in many computer programming languages. It is a combination of the English words and . When executed it causes an unconditional transfer of control (a jump ) to another statement. The jumped to statement is specified using… …   Wikipedia

  • goto — (от англ. go to  «перейти к»)  оператор безусловного перехода (перехода к определённой точке программы, обозначенной номером строки либо меткой) в некоторых языках программирования. В некоторых языках оператор безусловного перехода …   Википедия

  • GOTO — L instruction goto (de l anglais go to, en français aller à) est une instruction présente dans de nombreux langages de programmation. Elle est utilisée pour réaliser des sauts inconditionnels dans un programme. L exécution est renvoyée vers une… …   Wikipédia en Français

  • Gotō — Goto steht für: Sprunganweisung, einen Sprung in der Programmierung Goto (Teleskop), eine Vorrichtung an Teleskopen Verein der Künste Hauptsitz in Österreich Gotō (五島) steht außerdem für: Gotō Inseln, eine Inselgruppe in der japanischen Präfektur …   Deutsch Wikipedia

  • Goto — steht für: Sprunganweisung, einen Sprung in der Programmierung Goto (Teleskop), eine Vorrichtung an Teleskopen Gotō (五島) steht außerdem für: Gotō Inseln, eine Inselgruppe in der japanischen Präfektur Nagasaki Gotō (Nagasaki), eine Stadt auf… …   Deutsch Wikipedia

  • Gotō — shi (五島市) Plage d Omaha à Gotō Administration Pays Japon Région Kyūshū Préfecture …   Wikipédia en Français

  • Goto — puede referirse a: GOTO (ir a), instrucción de varios lenguajes de programación; Gotō, apellido japonés; Islas Gotō, archipiélago japonés. Esta página de desambiguación cataloga artículos relacionados con el mismo título. Si llegaste aquí a… …   Wikipedia Español

  • GOTO — o GO TO (ir a en inglés) es una sentencia o instrucción muy común en los lenguajes de programación con el objetivo de controlar el flujo del programa. El efecto de su versión más simple es transferir sin condiciones la ejecución del programa a la …   Enciclopedia Universal

  • goto — |ô| s. m. 1.  [Informal] Glote. 2. O que causa sufocação. 3. dar no goto: entrar na glote (a comida ou a bebida). 4.  [Figurado] Causar estranheza; agradar. • Plural: gotos |ô| …   Dicionário da Língua Portuguesa

Compartir el artículo y extractos

Link directo
Do a right-click on the link above
and select “Copy Link”