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