switch statement example ejemplos c switch-statement language-lawyer

statement - ¿Sintaxis válida pero inútil en switch-case?



switch case java (8)

¿Tiene esto algún propósito?

Sí. Si en lugar de una declaración, coloca una declaración antes de la primera etiqueta, esto puede tener mucho sentido:

switch (a) { int i; case 0: i = f(); g(); h(i); break; case 1: i = g(); f(); h(i); break; }

Las reglas para declaraciones y declaraciones se comparten para bloques en general, por lo que es la misma regla que permite que también permita declaraciones allí.

También vale la pena mencionar que si la primera declaración es una construcción de bucle, pueden aparecer etiquetas de caso en el cuerpo del bucle:

switch (i) { for (;;) { f(); case 1: g(); case 2: if (h()) break; } }

No escriba un código como este si hay una forma más legible de escribirlo, pero es perfectamente válido y se puede acceder a la llamada f() .

A través de un pequeño error tipográfico, encontré accidentalmente esta construcción:

int main(void) { char foo = ''c''; switch(foo) { printf("Cant Touch This/n"); // This line is Unreachable case ''a'': printf("A/n"); break; case ''b'': printf("B/n"); break; case ''c'': printf("C/n"); break; case ''d'': printf("D/n"); break; } return 0; }

Parece que el printf en la parte superior de la instrucción switch es válido, pero también completamente inalcanzable.

Obtuve una compilación limpia, sin siquiera una advertencia sobre el código inalcanzable, pero esto parece inútil.

¿Debe un compilador marcar esto como código inalcanzable?
¿Tiene esto algún propósito?


Cabe señalar que prácticamente no hay restricciones estructurales en el código dentro de la declaración de switch , o en el case *: etiquetas se colocan dentro de este código *. Esto hace posible programar trucos como el dispositivo de duff , cuya posible implementación se ve así:

int n = ...; int iterations = n/8; switch(n%8) { while(iterations--) { sum += *ptr++; case 7: sum += *ptr++; case 6: sum += *ptr++; case 5: sum += *ptr++; case 4: sum += *ptr++; case 3: sum += *ptr++; case 2: sum += *ptr++; case 1: sum += *ptr++; case 0: ; } }

Verá, el código entre el switch(n%8) { y el case 7: etiqueta es definitivamente accesible ...

* Como supercat señaló afortunadamente en un comentario : desde C99, ni un goto ni una etiqueta (ya sea un case *: etiqueta o no) pueden aparecer dentro del alcance de una declaración que contiene una declaración VLA. Por lo tanto, no es correcto decir que no hay restricciones estructurales en la ubicación del case *: etiquetas. Sin embargo, el dispositivo de Duff es anterior al estándar C99, y de todos modos no depende del VLA. Sin embargo, me sentí obligado a insertar un "virtualmente" en mi primera oración debido a esto.


Es posible implementar un "ciclo y medio" con él, aunque podría no ser la mejor manera de hacerlo:

char password[100]; switch(0) do { printf("Invalid password, try again./n"); default: read_password(password, sizeof(password)); } while (!is_valid_password(password));


Hay un uso famoso de este llamado en.wikipedia.org/wiki/Duff''s_device .

int n = (count+3)/4; switch (count % 4) { do { case 0: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while (--n > 0); }

Aquí copiamos un búfer apuntado por from a un búfer apuntado por to . count instancias de count de datos.

La declaración do{}while() comienza antes de la primera etiqueta del case , y las etiquetas de los case están incrustadas dentro del do{}while() .

Esto reduce el número de ramas condicionales al final del ciclo do{}while() encuentra aproximadamente por un factor de 4 (en este ejemplo; la constante se puede ajustar al valor que desee).

Ahora, los optimizadores a veces pueden hacer esto por usted (especialmente si están optimizando las instrucciones de transmisión / vectorizadas), pero sin la optimización guiada por perfil no pueden saber si espera que el bucle sea grande o no.

En general, las declaraciones de variables pueden ocurrir allí y usarse en todos los casos, pero estar fuera del alcance después de que finalice el cambio. (tenga en cuenta que se omitirá cualquier inicialización)

Además, el flujo de control que no es específico del interruptor puede llevarlo a esa sección del bloque de interruptores, como se ilustra arriba, o con un goto .


No solo para declaración variable sino también para salto avanzado. Puede utilizarlo bien si y solo si no es propenso al código de espagueti.

int main() { int i = 1; switch(i) { nocase: printf("no case/n"); case 0: printf("0/n"); break; case 1: printf("1/n"); goto nocase; } return 0; }

Huellas dactilares

1 no case 0 /* Notice how "0" prints even though i = 1 */

Cabe señalar que switch-case es una de las cláusulas de control de flujo más rápido. Por lo tanto, debe ser muy flexible para el programador, lo que a veces implica casos como este.


Quizás no sea el más útil, pero no del todo inútil. Puede usarlo para declarar una variable local disponible dentro del alcance del switch .

switch (foo) { int i; case 0: i = 0; //.... case 1: i = 1; //.... }

El estándar ( N1579 6.8.4.2/7 ) tiene la siguiente muestra:

EJEMPLO En el fragmento de programa artificial

switch (expr) { int i = 4; f(i); case 0: i = 17; /* falls through into default code */ default: printf("%d/n", i); }

el objeto cuyo identificador es i existe con una duración de almacenamiento automática (dentro del bloque) pero nunca se inicializa y, por lo tanto, si la expresión de control tiene un valor distinto de cero, la llamada a la función printf accederá a un valor indeterminado. Del mismo modo, no se puede acceder a la llamada a la función f .

PS BTW, la muestra no es un código C ++ válido. En ese caso ( N4140 6.7/3 , énfasis mío):

Un programa que salta 90 desde un punto donde una variable con duración de almacenamiento automático no está dentro del alcance hasta un punto donde está dentro del alcance está mal formado a menos que la variable tenga un tipo escalar , un tipo de clase con un constructor trivial predeterminado y un destructor trivial, una versión calificada para cv de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador (8.5).

90) La transferencia de la condición de una declaración de switch a una etiqueta de caso se considera un salto a este respecto.

Entonces reemplazando int i = 4; con int i; lo convierte en un C ++ válido.


Suponiendo que está utilizando gcc en Linux, le habría dado una advertencia si está utilizando 4.4 o una versión anterior.

La opción -Wunreachable-code se eliminó en gcc 4.4 en adelante.


-Wswitch-unreachable tu respuesta relacionada con la opción gcc requerida -Wswitch-unreachable para generar la advertencia, esta respuesta es elaborar en la parte de usabilidad / dignidad .

Citando directamente de C11 , capítulo §6.8.4.2, ( énfasis mío )

switch (expr) { int i = 4; f(i); case 0: i = 17; /* falls through into default code */ default: printf("%d/n", i); }

el objeto cuyo identificador es i existe con una duración de almacenamiento automática (dentro del bloque) pero nunca se inicializa y, por lo tanto, si la expresión de control tiene un valor distinto de cero, la llamada a la función printf accederá a un valor indeterminado. Del mismo modo, no se puede acceder a la llamada a la función f .

Lo cual se explica por sí mismo. Puede usar esto para definir una variable de ámbito local que esté disponible solo dentro del alcance de la instrucción de switch .