2012-03-16 21 views
26

Escribo un código C y en mi código tengo dos bucles anidados. En una condición particular quiero break fuera del lazo interno y continue el lazo externo. Traté de lograr esto usando una etiqueta al final en el código del lazo externo y, con la condición, esa etiqueta con el goto. Sin embargo, gcc da un error que no puedo tener una etiqueta al final de una declaración compuesta. Por qué no?En C, ¿por qué necesita una declaración después de una etiqueta goto?

Nota 1: Esta no es una declaración switchy que pregunta ha sido contestada elsewhere.

Nota 2: Esta no es una pregunta sobre el estilo y si debería o no debería estar usando declaraciones goto o variables condicionales en su lugar.

EDIT: La gente ha pedido un ejemplo y que pueden dar un ejemplo un poco fácil de comprobar si una matriz es un subconjunto de otro conjunto

int superArray[SUPER_SIZE] = {...}, subArray[SUB_SIZE] = {...}; 
    int superIndex, subIndex; 

    for (superIndex=0; superIndex<SUPER_SIZE-SUB_SIZE; superIndex+=1) 
    { 
     for (subIndex=0; subIndex<SUB_SIZE; subIndex+=1) 
     if (superArray[superIndex+subIndex] != subArray[subIndex]) 
      goto break_then_continue; 

     // code that executes if subArray is a sub array 

     break_then_continue: 
    } 
+3

¿Puede dar un pequeño programa que reproduce el mensaje de error que se obtiene? – sarnold

+0

buena suerte y cuidado con velociraptors – wim

Respuesta

34

En la norma se dijo explícitamente que las etiquetas pertenecen a una declaración, por lo tanto, un punto y coma sencilla (;) después de su La etiqueta puede eludir el problema al que se está ejecutando, ya que eso cuenta como una declaración.

incluso hay un ejemplo de la utilización de un "vacío " declaración en 6.8.3/6.

Ejemplo 3 Una declaración nula también se puede utilizar para llevar una etiqueta simplemente antes del cierre} de una instrucción compuesta

while (loop1) { 
    /* ... */ 

    while (loop2) { 
    /* ... */ 

    if (want_out) 
     goto end_loop1; 

    /* ... */ 
    } 

    /* ... */ 

    end_loop1: ; 
} 

En el este estándar se denomina a como null statement.


6.8.1 declaraciones Etiquetada

Syntax 
    1 labeled-statement: 
     identifier : statement 
     case constant-expression : statement 
     default : statement 

en cuenta que statement no es opcional en la cita anterior.


+0

+1 Gran respuesta. Me encanta el ejemplo tomado directamente del estándar. – Caleb

+0

Gracias por la excelente respuesta. Estaba buscando * por qué * 'gcc' funciona de la manera en que no lo hace para evitarlo. Sin embargo, su respuesta tiende a indicar que es simplemente la forma en que se escribe c. Esto es en gran parte un legado de cuando la compilación c era solo una pequeña abstracción del código ensamblador. – AntonDelprado

+0

@AntonDelprado En realidad es bastante simple, goto colocará la etiqueta antes del comando/expresión y si no existe tal cosa, no hay ningún lugar para saltar. Esa declaración vacía se usa, así que esto es posible. de esta manera, salta sobre un equivalente inofensivo de la función de ensamblaje NOP (sin operación). – AoeAoe

3

sólo hay que escribir:

label: ; 

El punto y coma es una declaración vacía. Lo necesitas porque el lenguaje se define así; necesita ir a una declaración, incluso si está vacía.

for (int i = 0; i < N; i++) 
    { 
     for (int j = 0; i < M; j++) 
     { 
      ... 
      if (some_condition) 
       goto continue_loop1; 
      ... 
     } 
continue_loop1: ; 
    } 

Puede discutir sobre la sangría en la etiqueta.

+0

También tenga en cuenta que una declaración, incluso con una inicialización, no es una declaración que se puede etiquetar: 'etiqueta1: int x = función (y, z);' no es válida. –

3

La etiqueta debe señalar a una afirmación.

C mandatos esto:

(C99, 6.8.1 declaraciones Etiquetada P4) " Cualquier declaración puede ser precedido por un prefijo que declara un identificador como un nombre de la etiqueta".

En su caso se puede utilizar una instrucción nula:

void foo(void) 
{ 
    goto bla; 

    bla: 
    ; 
} 

declaraciones nulos realizar ninguna operación.

O también se puede utilizar una sentencia compuesta (un bloque) si tiene declaraciones:

void foo(void) 
{ 
    goto bla; 

    bla: 
    { 
     int x = 42; 
     printf("%d\n", x); 
    } 
} 
Cuestiones relacionadas