Estoy programando C en cygwin windows. Después de haber hecho un poco de programación en C y de sentirme cómodo con el idioma, quise mirar debajo del capó y ver qué está haciendo el compilador para el código que escribo.Código de nivel de conjunto de caja de interruptor
Así que anotó un bloque de código que contiene sentencias de caso interruptor y las convirtió en el montaje usando:
gcc -S foo.c
Aquí está la fuente de C:
switch(i)
{
case 1:
{
printf("Case 1\n");
break;
}
case 2:
{ printf("Case 2\n");
break;
}
case 3:
{
printf("Case 3\n");
break;
}
case 4:
{
printf("Case 4\n");
break;
}
case 5:
{
printf("Case 5\n");
break;
}
case 6:
{
printf("Case 6\n");
break;
}
case 7:
{
printf("Case 7\n");
break;
}
case 8:
{
printf("Case 8\n");
break;
}
case 9:
{
printf("Case 9\n");
break;
}
case 10:
{
printf("Case 10\n");
break;
}
default:
{
printf("Nothing\n");
break;
}
}
Ahora, el conjunto resultante de la misma es :
movl $5, -4(%ebp)
cmpl $10, -4(%ebp)
ja L13
movl -4(%ebp), %eax
sall $2, %eax
movl L14(%eax), %eax
jmp *%eax
.section .rdata,"dr"
.align 4
L14:
.long L13
.long L3
.long L4
.long L5
.long L6
.long L7
.long L8
.long L9
.long L10
.long L11
.long L12
.text
L3:
movl $LC0, (%esp)
call _printf
jmp L2
L4:
movl $LC1, (%esp)
call _printf
jmp L2
L5:
movl $LC2, (%esp)
call _printf
jmp L2
L6:
movl $LC3, (%esp)
call _printf
jmp L2
L7:
movl $LC4, (%esp)
call _printf
jmp L2
L8:
movl $LC5, (%esp)
call _printf
jmp L2
L9:
movl $LC6, (%esp)
call _printf
jmp L2
L10:
movl $LC7, (%esp)
call _printf
jmp L2
L11:
movl $LC8, (%esp)
call _printf
jmp L2
L12:
movl $LC9, (%esp)
call _printf
jmp L2
L13:
movl $LC10, (%esp)
call _printf
L2:
Ahora, en el ensamblaje, el código es la primera comprobación del último caso (es decir, caso 10) primero. Esto es muy extraño. Y luego está copiando 'yo' en 'eax' y haciendo cosas que están más allá de mí.
He oído que el compilador implementa una tabla de salto para el interruptor ... caso. ¿Es lo que está haciendo este código? ¿O qué está haciendo y por qué? Porque en el caso de un menor número de casos, el código es bastante similar al generado para if ... else ladder, pero cuando aumenta el número de casos, se ve esta implementación inusual.
Gracias de antemano.
Desafortunadamente, no se optimiza para una búsqueda de tabla del puntero de cadena y una 'llamada _printf'. Ninguno de gcc/clang/icc hace eso incluso en '-O3'. https://godbolt.org/g/JrSwU3 (Sin embargo, optimizan 'printf' para' puts' y optimizan la llamada final a 'jmp' en lugar de a' call'/'ret') –