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 la printf
parte superior de la switch
declaración es válida, 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?
c
switch-statement
language-lawyer
abelenky
fuente
fuente
-Wswitch-unreachable
goto
entrar y salir de la parte inalcanzable, que puede ser útil para varios hacks.switch
es solo un condicionalgoto
con múltiples etiquetas. Hay más o menos las mismas restricciones en su cuerpo que las que tendría en un bloque de código regular lleno de etiquetas de goto.Respuestas:
Quizás no sea el más útil, pero no del todo inútil. Puede usarlo para declarar una variable local disponible dentro del
switch
alcance.El estándar (
N1579 6.8.4.2/7
) tiene la siguiente muestra:PS BTW, la muestra no es un código C ++ válido. En ese caso (
N4140 6.7/3
énfasis mío):Por lo que reemplazar
int i = 4;
conint i;
lo convierte en un C ++ válida.fuente
i
se inicializó a 4, ¿qué me estoy perdiendo?static
, se inicializará a cero, por lo que también hay un uso seguro para esto.i = 4;
inicialización, por lo que nunca tiene lugar.case
, y siempre tenía que usar diferentes nombres en cada unacase
o definirla fuera del interruptor.Si. Si en lugar de una declaración, coloca una declaración antes de la primera etiqueta, esto puede tener mucho sentido:
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 instrucción es una construcción de bucle, pueden aparecer etiquetas de caso en el cuerpo del bucle:
No escriba un código como este si hay una forma más legible de escribirlo, pero es perfectamente válido y
f()
se puede acceder a la llamada.fuente
{ /*code*/ switch(x) { } }
puede parecer más limpio, pero también está mal .Hay un uso famoso de este llamado Dispositivo de Duff .
Aquí copiamos un búfer señalado por
from
a un búfer apuntado porto
. Copiamoscount
instancias de datos.La
do{}while()
declaración comienza antes de la primeracase
etiqueta, y lascase
etiquetas están incrustadas dentro dedo{}while()
.Esto reduce el número de ramas condicionales al final del
do{}while()
ciclo encontradas por aproximadamente 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
.fuente
do {
ycase 0:
no importa, ambos sirven para colocar un objetivo de salto en el primero*to = *from++;
.do {
es más legible. Sí, discutir sobre la legibilidad para el dispositivo de Duff es estúpido e inútil y probablemente sea una forma simple de volverse loco.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.
fuente
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.
Huellas dactilares
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.
fuente
nocase:
ydefault:
?i=4
no se disparanocase
.Cabe señalar que prácticamente no hay restricciones estructurales en el código dentro de la
switch
declaración o en el lugar dondecase *:
se colocan las etiquetas dentro de este código *. Esto hace posible trucos de programación como el dispositivo de duff , una implementación posible que se ve así:Verá, el código entre el
switch(n%8) {
y lacase 7:
etiqueta es definitivamente accesible ...* Como supercat señaló afortunadamente en un comentario : desde C99,
goto
ni una etiqueta ni una etiqueta (ya sea unacase *:
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 colocación de lascase *:
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.fuente
goto
niswitch/case/default
puede aparecer dentro del alcance de cualquier objeto o tipo declarado de forma variable. Esto significa efectivamente que si un bloque contiene cualquier declaración de objetos o tipos de matriz de longitud variable, cualquier etiqueta debe preceder a esas declaraciones. Hay un poco de palabrería confusa en el Estándar que sugiere que en algunos casos el alcance de una declaración VLA se extiende a la totalidad de una declaración de cambio; ver stackoverflow.com/questions/41752072/… para mi pregunta sobre eso.Obtuviste tu respuesta relacionada con la opción requerida
gcc
-Wswitch-unreachable
para generar la advertencia, esta respuesta es elaborar la parte de usabilidad / dignidad .Citando directamente del
C11
capítulo §6.8.4.2, ( énfasis mío )Lo cual se explica por sí mismo. Puede usar esto para definir una variable de ámbito local que esté disponible solo dentro del
switch
alcance de la instrucción.fuente
Es posible implementar un "ciclo y medio" con él, aunque podría no ser la mejor manera de hacerlo:
fuente