Uso de switch en programación
Orange switches artwork. Valentin Ruhry. |
switch
en C/C++ o Java? ¿Por qué los profesores insisten en que lo usemos, porque es más bonito? ¡Pues sí! No olvides que un código claro favorece una lectura más comprensible.
Pero no somos nosotros los únicos que nos beneficiaremos: nuestro programa puede ser más eficiente. Recuerda que cuantas más y mejores pistas demos al compilador, mejor código podrá generar.
Es cierto que un
switch
tiene el mismo diagrama de flujo que un if-else
, pero es más estricto respecto a la condición. En primer lugar sólo admite expresiones constantes, y en segundo estamos usando etiquetas, con lo que se lo estamos poniendo muy fácil al compilador para que genere una tabla de functores.
Precaución: no utilices etiquetas y sentencias
goto
en C/C++.Por ejemplo, supongamos este sencillo código en C:
if (x == 1) a(); else if (x == 2) b(); else if (x == 3) c(); else if (x == 5) d(); else error();Es muy fácil traducirlo a una sentencia
switch
:
switch (x) { case 1: a(); break; case 2: b(); break; case 3: c(); break; case 5: d(); break; default: error(); }Pero, ¿qué hará el compilador? ¿Lo mismo que si hubiéramos escrito lo primero? No, si puede evitarlo. Los valores constantes son muy próximos entre sí, y evaluar todas las condiciones una a una sería muy costoso. La idea es equivalente al siguiente código, que emplea un vector de punteros a función (nótese que debemos tener en cuenta los casos 0 y 4):
void (*funciones[])() = { error, a, b, c, error, d }; if (x > 5) error(); else funciones[x]();De esta forma con una sola condición (el
default
) y una suma saltaremos directamente a la función correcta.
Consejo: Tanto si utilizas
if-else
como switch
, escribe siempre primero aquellas condiciones que tegan mayor probabilidad de acertar. En el primer caso, o si switch
no se puede optimizar, evitaremos hacer demasiadas comparaciones. Si switch
se puede optimizar, el compilador ordenará todas las condiciones.Experimento
Hemos creado una sentenciaif-else
con 1.000 condiciones, su orden switch
y su vector de functores equivalentes, en un archivo de sólo 10.025 líneas de código. No lo hemos escrito a mano, nos hemos servido de un programita en Python para generarlo. Lo hemos compilado con GNU CC, hemos ejecutado 108 pruebas, y estos son los resultados:
Procesador: Intel Core i7 @ 2,2 GHz
Compilador: g++ 4.8.1 / -Ofast
S.O.: Ubuntu 13.10 x86_64
|
El código fuente está disponible en este enlace:
Avanzado
Cabe mencionar que Microsoft Visual C++ es capaz de optimizar algunas estructurasif-else
como la de arriba, de igual forma que si se hubiera escrito con switch
, aunque no es capaz de compilar un programa tan complejo como el anterior, hay que bajar de 1.000 a 500 condiciones. Aquí os dejo una versión simplificada de la salida en ensamblador del compilador GCC con el código switch
de arriba (véase el comentario en las instrucciones de salto):
movl x, %eax cmpl $5, %eax ja DEF ; if (x > 5) goto DEF movl BASE(,%eax,4), %eax jmp *%eax ; goto (BASE + x) BASE: .long DEF .long L1 .long L2 .long L3 .long DEF .long L5< L1: call a jmp END .L2: call b jmp END .L3: call c jmp END .L5: call d jmp END DEF: call error
Comentarios
Publicar un comentario