¿Por qué tenemos que usar el interruptor break in?

65

¿Quién decidió, y basándose en qué conceptos, que switch construcción (en muchos idiomas) tiene que ser, como es? ¿Por qué tenemos que usar break en cada declaración? ¿Por qué tenemos que escribir algo como esto:

switch(a)
{
    case 1:
        result = 'one';
        break;
    case 2:
        result = 'two';
        break;
    default:
        result = 'not determined';
        break;
}

(He notado esta construcción en PHP y JS, pero probablemente hay muchos otros idiomas que la usan)

Si switch es una alternativa de if , ¿por qué no podemos usar la misma construcción para switch , como para if ? Es decir:

switch(a)
{
    case 1:
    {
        result = 'one';
    }
    case 2:
    {
        result = 'two';
    }
    default:
    {
        result = 'not determined';
    }
}

Se dice que break impide la ejecución de bloques que siguen a uno actual. Pero, ¿alguien realmente se encuentra en una situación en la que haya necesidad de ejecutar el bloque actual y los siguientes? No lo hice Para mí, break siempre está ahí. En cada cuadra. En cada código.

    
pregunta trejder 28.08.2012 - 11:16

11 respuestas

89

C fue uno de los primeros idiomas en tener la declaración switch en esta forma, y todos los otros idiomas principales lo heredaron de allí, y en su mayoría eligieron mantener la semántica de C por defecto. Tampoco pensaron en las ventajas. de cambiarlo, o juzgarlo como menos importante que mantener el comportamiento al que todos estaban acostumbrados.

En cuanto a por qué C se diseñó de esa manera, probablemente se derive del concepto de C como "ensamblaje portátil". La declaración switch es básicamente una abstracción de una tabla de rama , y una tabla de rama también tiene un implícito paso a paso y requiere una instrucción de salto adicional para evitarlo.

Básicamente, los diseñadores de C también optaron por mantener la semántica del ensamblador por defecto.

    
respondido por el Michael Borgwardt 28.08.2012 - 12:40
82

Porque switch no es una alternativa de las declaraciones if ... else en esos idiomas.

Al usar switch , podemos hacer coincidir más de una condición a la vez, lo cual es muy apreciado en algunos casos.

Ejemplo:

public Season SeasonFromMonth(Month month)
{
    Season season;
    switch (month)
    {
        case Month.December:
        case Month.January:
        case Month.February:
            season = Season.Winter;
            break;

        case Month.March:
        case Month.April:
        case Month.May:
            season = Season.Spring;
            break;

        case Month.June:
        case Month.July:
        case Month.August:
            season = Season.Summer;
            break;

        default:
            season = Season.Autumn;
            break;
    }

    return season;
}
    
respondido por el Satish Pandey 28.08.2012 - 11:21
13

Esto se ha preguntado sobre Desbordamiento de pila en el contexto de C: ¿Por qué la declaración de cambio fue diseñada para necesitar un descanso?

Para resumir la respuesta aceptada, probablemente fue un error. La mayoría de los otros lenguajes probablemente solo siguieron a C. Sin embargo, algunos lenguajes como C # parecen haber solucionado esto permitiendo el paso directo, pero solo cuando el programador lo dice explícitamente (fuente: el enlace de arriba, no hablo C # por mi cuenta) .

    
respondido por el Tapio 28.08.2012 - 11:36
9

Voy a responder con un ejemplo. Si desea indicar el número de días para cada mes de un año, es obvio que algunos meses tienen 31, unos 30 y 1 28/29. Se vería así,

switch(month) {
    case 4:
    case 6:
    case 9:
    case 11;
        days = 30;
        break;
    case 2:
        //Find out if is leap year( divisible by 4 and all that other stuff)
        days = 28 or 29;
        break;
    default:
        days = 31;
}

Este es un ejemplo en el que varios casos tienen el mismo efecto y se agrupan todos juntos. Obviamente, había una razón para la elección de la palabra clave break y no la if ... else if construct.

Lo principal a tomar en cuenta aquí es que una declaración switch con muchos casos similares no es un si ... más si ... más si ... más para cada uno de los casos, pero if (1, 2, 3) ... else if (4,5,6) else ...

    
respondido por el Awemo 28.08.2012 - 11:50
8

Hay dos situaciones en las que puede suceder que “caiga” de un caso a otro: el caso vacío:

switch ( ... )
{
  case 1:
  case 2:
    do_something_for_1_and_2();
    break;
  ...
}

y el caso no vacío

switch ( ... )
{
  case 1:
    do_something_for_1();
    /* Deliberately fall through */
  case 2:
    do_something_for_1_and_2();
    break;
...
}

A pesar de la referencia a Duff's Device , las instancias legítimas para el segundo caso son pocas y distantes, y en general Prohibido por los estándares de codificación y marcado durante el análisis estático. Y donde se encuentra, es más a menudo debido a la omisión de un break .

El primero es perfectamente sensible y común.

Para ser honesto, no veo ninguna razón para necesitar el break y el analizador de idioma sabiendo que un cuerpo de un caso vacío es una caída, mientras que un caso no vacío es independiente.

Es una pena que el panel de ISO C parezca más preocupado por agregar características nuevas (no deseadas) y mal definidas al lenguaje, en lugar de corregir las características no definidas, no especificadas o definidas por la implementación, por no mencionar lo ilógico.

    
respondido por el Andrew 28.08.2012 - 12:09
4

No forzar el break permite una serie de cosas que podrían ser difíciles de hacer. Otros han observado casos de agrupación, para los cuales hay una serie de casos no triviales.

Un caso en el que es imperativo que no se use break es Dispositivo de Duff . Esto se utiliza para " desenrollar " bucles donde puede acelerar las operaciones al limitar el número de comparaciones requeridas. Creo que el uso inicial permitía una funcionalidad que anteriormente había sido demasiado lenta con un bucle completamente enrollado. En algunos casos se comercializa el tamaño del código por velocidad.

Es una buena práctica reemplazar el break con un comentario apropiado, si el caso tiene algún código. De lo contrario, alguien arreglará el break faltante e introducirá un error.

    
respondido por el BillThor 29.08.2012 - 05:20
2

En C, donde el origen parece ser, el bloque de código de la instrucción switch no es una construcción especial. Es un bloque de código normal, al igual que un bloque en una declaración if .

switch ()
{
}

if ()
{
}

case y default son etiquetas de salto dentro de este bloque, específicamente relacionadas con switch . Se manejan igual que las etiquetas de salto normales para goto . Hay una regla específica que es importante aquí: las etiquetas de salto pueden estar en casi todas partes del código, sin interrumpir el flujo de código.

Como bloque de código normal, no es necesario que sea una instrucción compuesta. Las etiquetas son opcionales, también. Estas son declaraciones de switch válidas en C:

switch (a)
    case 1: Foo();

switch (a)
    Foo();

switch (a)
{
    Foo();
}

El propio estándar de C da esto como ejemplo (6.8.4.2):

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

En el fragmento de programa artificial, el objeto cuyo identificador es i existe   con duración de almacenamiento automático (dentro del bloque) pero nunca se inicializa,   y así, si la expresión de control tiene un valor distinto de cero, la llamada a la   La función printf accederá a un valor indeterminado. Del mismo modo, la llamada a la   No se puede alcanzar la función f.

Además, default también es una etiqueta de salto, y por lo tanto puede estar en cualquier lugar, sin la necesidad de ser el último caso.

Esto también explica el dispositivo de Duff:

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

¿Por qué la caída? Debido a que en el flujo de código normal en un bloque de código normal, el paso a la siguiente declaración es esperado , tal como lo esperaría en un bloque de código if .

if (a == b)
{
    Foo();
    /* "Fall-through" to Bar expected here. */
    Bar();
}

switch (a)
{
    case 1: 
        Foo();
        /* Automatic break would violate expected code execution semantics. */
    case 2:
        Bar();
}

Mi conjetura es que la razón de esto fue la facilidad de implementación. No necesita un código especial para analizar y compilar un bloque switch , cuidar de reglas especiales. Simplemente lo analiza como cualquier otro código y solo tiene que cuidar las etiquetas y la selección de salto.

Una pregunta de seguimiento interesante de todo esto es si las siguientes declaraciones anidadas se imprimen "Hecho". o no.

int a = 10;

switch (a)
{
    switch (a)
    {
        case 10: printf("Done.\n");
    }
}

El estándar C se preocupa por esto (6.8.4.2.4):

  

Se puede acceder a una etiqueta de caso o por defecto solo dentro de la declaración de cambio de cierre más cercana.

    
respondido por el Secure 29.08.2012 - 07:49
1

Varias personas ya han mencionado la noción de combinar múltiples condiciones, lo cual es muy valioso de vez en cuando. Sin embargo, la capacidad de hacer coincidir varias condiciones no requiere necesariamente que haga exactamente lo mismo con cada condición que coincida. Considera lo siguiente:

switch (someCase)
{
    case 1:
    case 2:
        doSomething1And2();
        break;

    case 3:
        doSomething3();

    case 4:
        doSomething3And4();
        break;

    default:
        throw new Error("Invalid Case");
}

Hay dos formas diferentes en que se combinan conjuntos de condiciones múltiples aquí. Con las condiciones 1 y 2, simplemente caen en la misma trama de código y hacen exactamente lo mismo. Sin embargo, con las condiciones 3 y 4, aunque ambas terminan llamando a doSomething3And4() , solo 3 llamadas doSomething3() .

    
respondido por el Panzercrisis 18.12.2014 - 16:53
1

Para responder a dos de tus preguntas.

¿Por qué C necesita saltos?

Se reduce a las raíces de Cs como un "ensamblador portátil". Donde el código de psudo como este era común: -

    targets=(addr1,addr2,addr3);
    opt = 1  ## or 0 or 2
switch:
    br targets[opt]  ## go to addr2 
addr1:
    do 1stuff
    br switchend
addr2:
    do 2stuff
    br switchend
addr3
    do 3stuff
switchend:
    ......

la declaración de cambio fue diseñada para proporcionar una funcionalidad similar a un nivel superior.

¿Alguna vez tenemos interruptores sin interrupciones?

Sí, esto es bastante común y hay algunos casos de uso;

En primer lugar, es posible que desee realizar la misma acción en varios casos. Hacemos esto apilando los casos uno encima del otro:

case 6:
case 9:
    // six or nine code

Otro caso de uso común en las máquinas de estado es que después de procesar un estado, inmediatamente queremos ingresar y procesar otro estado:

case 9:
    crashed()
    newstate=10;
case 10:
    claim_damage();
    break;
    
respondido por el James Anderson 18.12.2014 - 09:51
-2

La declaración de interrupción es una instrucción de salto que le permite al usuario salir del interruptor de cierre más cercano (para su caso), mientras que, do, for o foreach. es tan fácil como eso.

    
respondido por el jasper 28.08.2012 - 19:39
-3

Creo que con todo lo escrito anteriormente, el resultado principal de este hilo es que si va a diseñar un nuevo idioma, el valor predeterminado debería ser que no es necesario agregar una declaración break y el compilador lo tratará como si lo hicieras.

Si desea ese caso raro en el que desea continuar con el siguiente caso, simplemente indíquelo con una declaración continue .

Esto se puede mejorar de modo que solo si usa llaves dentro de la caja, no se encienda, por lo que el ejemplo con los meses anteriores de varios casos que realizan el mismo código exacto siempre funcionará como se espera sin necesidad de continue .

    
respondido por el ethans 05.09.2012 - 07:39

Lea otras preguntas en las etiquetas