republica que por itau inversiones internacionales instructivo importaciones importacion formulario exterior declaración declaracion comercio codigos cambio bienes banco c switch-statement

que - instructivo declaración de cambio por importaciones de bienes



Declaración de cambio: debe ser el último caso por defecto? (10)

Considere la siguiente declaración de switch :

switch( value ) { case 1: return 1; default: value++; // fall-through case 2: return value * 2; }

Este código se compila, pero ¿es válido (= comportamiento definido) para C90 / C99? Nunca he visto código donde el caso predeterminado no es el último caso.

EDITAR:
Como escriben Jon Cage y KillianDS : este es un código realmente feo y confuso, y lo conozco muy bien. Solo me interesa la sintaxis general (¿está definida?) Y el resultado esperado.


Acompañando con otro ejemplo: esto puede ser útil si "por defecto" es un caso inesperado, y desea registrar el error, pero también hacer algo sensato. Ejemplo de algunos de mi propio código:

switch (style) { default: MSPUB_DEBUG_MSG(("Couldn''t match dash style, using solid line./n")); case SOLID: return Dash(0, RECT_DOT); case DASH_SYS: { Dash ret(shapeLineWidth, dotStyle); ret.m_dots.push_back(Dot(1, 3 * shapeLineWidth)); return ret; } // more cases follow }


El estándar C99 no es explícito sobre esto, pero tomando todos los hechos en conjunto, es perfectamente válido.

Un case y una etiqueta default son equivalentes a una etiqueta goto . Ver 6.8.1 Declaraciones etiquetadas. Especialmente interesante es 6.8.1.4, que habilita el dispositivo Duff ya mencionado:

Cualquier declaración puede estar precedida por un prefijo que declara un identificador como un nombre de etiqueta. Las etiquetas en sí mismas no alteran el flujo de control, que continúa sin obstáculos a través de ellas.

Editar : El código dentro de un interruptor no es nada especial; es un bloque normal de código como en una declaración if , con etiquetas de salto adicionales. Esto explica el comportamiento de caída y por qué es necesario break .

6.8.4.2.7 incluso da un ejemplo:

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 función printf tendrá acceso a un valor indeterminado. Del mismo modo, la llamada a la función f no puede ser alcanzada.

Las constantes de mayúsculas y minúsculas deben ser exclusivas dentro de una sentencia switch:

6.8.4.2.3 La expresión de cada etiqueta de caso debe ser una expresión constante y no dos expresiones de constante de caso en la misma instrucción de conmutación tendrán el mismo valor después de la conversión. Puede haber como máximo una etiqueta predeterminada en una declaración de cambio.

Todos los casos son evaluados, luego salta a la etiqueta predeterminada, si se les da:

6.8.4.2.5 Las promociones enteras se realizan en la expresión de control. La expresión constante en cada etiqueta de caso se convierte al tipo promocionado de la expresión de control. Si un valor convertido coincide con el de la expresión de control promovida, el control salta a la instrucción que sigue a la etiqueta de la caja coincidente. De lo contrario, si hay una etiqueta predeterminada, el control salta a la declaración etiquetada. Si no coincide ninguna expresión de constante de caso convertido y no hay una etiqueta predeterminada, no se ejecuta ninguna parte del cuerpo del interruptor.


Es válido y muy útil en algunos casos.

Considera el siguiente código:

switch(poll(fds, 1, 1000000)){ default: // here goes the normal case : some events occured break; case 0: // here goes the timeout case break; case -1: // some error occurred, you have to check errno }

El punto es que el código anterior es más legible y eficiente que en cascada if . Puede poner por defecto al final, pero no tiene sentido, ya que centrará su atención en los casos de error en lugar de casos normales (que aquí es el caso por default ).

En realidad, no es un buen ejemplo, en una encuesta sabes cuántos eventos pueden ocurrir como máximo. Mi verdadero punto es que hay casos con un conjunto definido de valores de entrada donde hay ''excepciones'' y casos normales. Si es mejor poner excepciones o casos normales al frente es una cuestión de elección.

En el campo del software, pienso en otro caso muy habitual: recursiones con algunos valores terminales. Si puede expresarlo usando un interruptor, por default será el valor usual que contiene la llamada recursiva y los elementos distinguidos (casos individuales) los valores del terminal. Por lo general, no es necesario centrarse en los valores de los terminales.

Otra razón es que el orden de los casos puede cambiar el comportamiento del código compilado, y eso es importante para las actuaciones. La mayoría de los compiladores generarán código de ensamblado compilado en el mismo orden en que aparece el código en el conmutador. Eso hace que el primer caso sea muy diferente de los demás: todos los casos, excepto el primero, implicarán un salto y que vaciarán las tuberías del procesador. Puede entenderlo como el predictor de bifurcación predeterminado para ejecutar el primer caso que aparece en el interruptor. Si un caso es mucho más común que los demás, entonces tiene muy buenas razones para ponerlo como el primer caso.

Leer comentarios es la razón específica por la que el póster original hizo esa pregunta después de leer la reorganización de Branch Loop del compilador Intel sobre optimización de código.

Entonces se convertirá en algún arbitraje entre la legibilidad del código y el rendimiento del código. Probablemente sea mejor poner un comentario para explicar al lector futuro por qué un caso aparece primero.


Es válido, pero bastante desagradable. Yo sugeriría que generalmente es malo permitir errores, ya que puede conducir a un código de espagueti muy complicado.

Es casi seguro que es mejor dividir estos casos en varias instrucciones de conmutación o funciones más pequeñas.

[edit] @Tristopia: Tu ejemplo:

Example from UCS-2 to UTF-8 conversion r is the destination array, wc is the input wchar_t switch(utf8_length) { /* Note: code falls through cases! */ case 3: r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; case 2: r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; case 1: r[0] = wc; }

sería más claro en cuanto a su intención (creo) si se escribiera así:

if( utf8_length >= 1 ) { r[0] = wc; if( utf8_length >= 2 ) { r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; if( utf8_length == 3 ) { r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; } } }

[edit2] @Tristopia: Su segundo ejemplo es probablemente el ejemplo más claro de un buen uso para el seguimiento:

for(i=0; s[i]; i++) { switch(s[i]) { case ''"'': case ''/''': case ''//': d[dlen++] = ''//'; /* fall through */ default: d[dlen++] = s[i]; } }

..pero personalmente dividiría el reconocimiento de comentarios en su propia función:

bool isComment(char charInQuestion) { bool charIsComment = false; switch(charInQuestion) { case ''"'': case ''/''': case ''//': charIsComment = true; default: charIsComment = false; } return charIsComment; } for(i=0; s[i]; i++) { if( isComment(s[i]) ) { d[dlen++] = ''//'; } d[dlen++] = s[i]; }


Hay casos en que está convirtiendo ENUM a una cadena o convirtiendo una cadena a enum en caso de que esté escribiendo / leyendo a / desde un archivo.

A veces es necesario establecer uno de los valores predeterminados para cubrir los errores cometidos editando archivos manualmente.

switch(textureMode) { case ModeTiled: default: // write to a file "tiled" break; case ModeStretched: // write to a file "stretched" break; }


La condición "predeterminada" puede estar en cualquier lugar dentro del interruptor que pueda existir una cláusula de caso. No se requiere que sea la última cláusula. He visto código que pone el valor predeterminado como la primera cláusula. El "caso 2:" se ejecuta normalmente, aunque la cláusula predeterminada esté por encima de él.

Como prueba, puse el código de muestra en una función, llamada test (int value) {} y ejecuté:

printf("0=%d/n", test(0)); printf("1=%d/n", test(1)); printf("2=%d/n", test(2)); printf("3=%d/n", test(3)); printf("4=%d/n", test(4));

El resultado es:

0=2 1=1 2=4 3=8 4=10


Los enunciados de caso y la declaración predeterminada pueden aparecer en cualquier orden en la instrucción switch. La cláusula predeterminada es una cláusula opcional que se corresponde si ninguna de las constantes en las declaraciones de casos se puede combinar.

Buen ejemplo :-

switch(5) { case 1: echo "1"; break; case 2: default: echo "2, default"; break; case 3; echo "3"; break; } Outputs ''2,default''

muy útil si quiere que sus casos se presenten en un orden lógico en el código (como en, sin decir caso 1, caso 3, caso 2 / predeterminado) y sus casos son muy largos, por lo que no desea repetir todo el caso código en la parte inferior para el valor predeterminado


No hay un orden definido en una declaración de cambio. Puede ver los casos como algo así como una etiqueta con nombre, como una etiqueta goto . Contrariamente a lo que la gente parece pensar aquí, en el caso del valor 2 la etiqueta predeterminada no se salta a. Para ilustrar con un ejemplo clásico, aquí está el dispositivo de Duff , que es el poster de los extremos de switch/case en C.

send(to, from, count) register short *to, *from; register count; { register n=(count+7)/8; 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); } }


Un escenario donde consideraría apropiado tener un ''predeterminado'' ubicado en algún lugar que no sea el final de una declaración de caso es en una máquina de estado donde un estado inválido debe reiniciar la máquina y proceder como si fuera el estado inicial. Por ejemplo:

switch(widget_state) { default: /* Fell off the rails--reset and continue */ widget_state = WIDGET_START; /* Fall through */ case WIDGET_START: ... break; case WIDGET_WHATEVER: ... break; }

una disposición alternativa, si un estado inválido no debe reiniciar la máquina pero debe ser fácilmente identificable como un estado inválido:

switch(widget_state) { case WIDGET_IDLE: widget_ready = 0; widget_hardware_off(); break; case WIDGET_START: ... break; case WIDGET_WHATEVER: ... break; default: widget_state = WIDGET_INVALID_STATE; /* Fall through */ case WIDGET_INVALID_STATE: widget_ready = 0; widget_hardware_off(); ... do whatever else is necessary to establish a "safe" condition }

En otro lugar, el código puede verificar (widget_state == WIDGET_INVALID_STATE) y proporcionar el comportamiento de informe de errores o restablecimiento del estado que parezca apropiado. Por ejemplo, el código de barra de estado podría mostrar un icono de error, y la opción del menú "iniciar widget" que está deshabilitada en la mayoría de los estados no inactivos podría habilitarse para WIDGET_INVALID_STATE y WIDGET_IDLE.


sí, esto es válido y, en algunas circunstancias, incluso es útil. En general, si no lo necesita, no lo haga.