Ver Mensaje Individual
  #10 (permalink)  
Antiguo 04/05/2010, 12:12
emi_ramo
 
Fecha de Ingreso: mayo-2008
Mensajes: 3
Antigüedad: 16 años, 6 meses
Puntos: 0
Respuesta: Uso del Go to

(Sé que el foro este es viejo, pero para que quede constancia... :D )

Cita:
Iniciado por X.Cyclop Ver Mensaje
Eso C no lo acepta por el "int", ¿no?
Ah ok. Porque había leido algo así pero no estoy muy seguro.
C sí que acepta la declaración de variables dentro de un for, pues este abre un nuevo bloque. La estructura ampliada de este for sería esta:

Código:
(aquí i todavía no existe)

{
   int i;

   while(i < 10)
   {
       i++;
   }
}

(aquí i ya no existe)
En cuanto al uso del goto, MaxExtreme ha dado un buen ejemplo. El problema más grande es que rompe el flujo de ejecución de formas no convencionales y muchas veces tampoco lógicas. Programando, deberías ser capaz de limitarte a usar los controladores de flujo if, else if, else, switch, while, do while y for, pudiendo modificar su comportamiento con break, continue y return. Así, todos sabremos cual es la intención en cada línea del programa, incluído tú cuando ya no te acuerdes de lo que hiciste y necesites revisarlo.

Pongamos un ejemplo con el que me he topado hoy mismo:

Con goto:
Código:
int funcion(int i) {
   if(i > 0)
      goto out;

   err = func(i);

   if(err) {
      i = err;
      goto error_cancel;
   }

   err = func2(&i);

   if(err) {
      i = err;
      goto error_cancel;
   }

   if(i < 0)
      goto out_end;

out:
   return i;

error_cancel:
   printf("error\n");
   goto out;

out_end:
   printf("todo bien\n");
   goto out;
}


Sin goto (corregidme si me equivoco):

Código:
int funcion(int i) {
   if(i < 0) {
      err = func(i);
      
      if(err) {
         i = err;
         printf("error\n");
      }
      else {
         err = func2(&i);
         
         if(err) {
            i = err;
            printf("error\n");
         }
         else if(i < 0) {
            printf("todo bien\n");
         }
      }
   }
   
   return i;
}
Como podéis ver, usando una buena tabulación es posible comprender rápidamente la lógica/el flujo de la función, sin necesidad de leer, entender y reencontrar nuevas palabras, como out, out_end y error_cancel en este caso. En este caso hemos tenido suerte y nos hemos encontrado con todas las etiquetas al final de la función. Así y todo no es tan sencillo ni estándar.

También habréis notado que en el segundo caso (sin goto) he tenido que escribir dos veces printf("error"); en vez de uno como en el primer caso. En este ejemplo es una tontería y no conlleva mayores problemas. En otros casos, escribir un error puede implicar muchas líneas. En tal caso, lo recomendado sería crear una nueva función, en este caso podría ser error(), que se encargaría de aglutinar las líneas necesarias para esta tarea y que, incluso, podría admitir parámetros y dar un error personalizado, dependiendo de qué haya fallado. La creación de una nueva función podría ser ineficiente para algunos casos. En estos, sería recomendable usar una función de tipo #define:

Código:
#define error(_err_) { \
   printf("Ha ocurrido un error: %d", (_err_)); \
   (...lo que sea...) \
}
que se "compilaría" en tiempo de preprocesador, llevando el bloque del define hacia donde haya sido usado antes de que pase el compilador. Esto nos ayuda a "mantener el orden" mientras no se pierde en eficiencia.