我正在使用Cygwin Windows编程。在进行了一些C语言编程并熟悉了这门语言后,我想看看编译器为我编写的代码做了什么操作。
因此,我编写了一个包含switch case语句的代码块,并使用以下方法将其转换为汇编:
gcc -S foo.c
以下是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;
}
}
现在的汇编代码如下:
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:
现在,在汇编中,代码首先检查最后一种情况(即第10种情况)。这很奇怪。然后它将“i”复制到“eax”中并执行我无法理解的操作。
我听说编译器为switch..case实现了一些跳转表,这就是这段代码在做什么吗?或者它在做什么以及为什么这样做?因为在少数情况下, 该代码与生成if...else梯形时非常相似,但当情况数量增加时,会出现这种不寻常的实现。
提前致谢。
call _printf
。即使在-O3
下,gcc/clang/icc也都没有这样做。https://godbolt.org/g/JrSwU3(但是它们会将`printf`优化为`puts`,并将尾调用优化为`jmp`而不是`call`/`ret`)。 - Peter Cordes