在c语言中switch语句会被实现为一个跳转表,跳转表是一个数组,这个数组里面存的都是地址,也就是说只要你传递给它一个i,他就会返回给你,你所需要跳转的地址,这样做得好处就是执行语句的时间和条件的个数无关..不过在gcc里面他也只是条件数大于4个,才会生成这个跳转表.
请看下面的代码:
[code]int switch_eg(int x)
{
int result = x;
switch (x) {
case 100:
result *= 13;
break;
case 102:
result += 10;
/* Fall through */
case 103:
result += 11;
break;
case 104:
case 106:
result *= result;
break;
default:
result = 0;
}
return result;
} [/code]
这只是一段简单的switch语句,下面我们用一段c代码来描述汇编代码所要做得事情.
[code]code *jt[7] = {
loc_A, loc_def, loc_B, loc_C,
loc_D, loc_def, loc_D
};
int switch_eg_impl(int x)
{
unsigned xi = x - 100;
int result = x;
if (xi > 6)
goto loc_def;
/* Next goto is not legal C */
goto jt[xi];
loc_A: /* Case 100 */
result *= 13;
goto done;
loc_B: /* Case 102 */
result += 10;
/* Fall through */
loc_C: /* Case 103 */
result += 11;
goto done;
loc_D: /* Cases 104, 106 */
result *= result;
goto done;
loc_def: /* Default case*/
result = 0;
done:
return result;
} [/code]
看上面的代码就很清楚了,它会对传进来的值与100进行一个减法,然后再将这个值传进switch语句.
而真实的汇编代码是怎么样的呢,我们可以看看:
[code]switch_eg:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax //这边得到传进来的参数
leal -100(%eax), %edx //这边将得到的参数和100做差
cmpl $6, %edx //这边和6比较,如果大于6说明下面的条件没有满足的所以默认进入default
jbe .L11
.L2:
popl %ebp
xorl %eax, %eax
ret
.p2align 4,,7
.L11:
jmp *.L7(,%edx,4) //这边也就是我们上面伪码所描述的那个jt[xi]
.section .rodata
.align 4
.align 4
.L7: //这边就是所构造的跳转表.
.long .L3
.long .L2
.long .L4
.long .L5
.long .L6
.long .L2
.long .L6
.text
.L6: // loc_D
imull %eax, %eax
popl %ebp
.p2align 4,,6
ret
.L5: //loc_c
popl %ebp
movl $114, %eax
.p2align 4,,6
ret
.L4: //loc_B
popl %ebp
movl $123, %eax
.p2align 4,,4
ret
.L3: //loc_A
popl %ebp
movl $1300, %eax
.p2align 4,,4
ret[/code]
请看下面的代码:
[code]int switch_eg(int x)
{
int result = x;
switch (x) {
case 100:
result *= 13;
break;
case 102:
result += 10;
/* Fall through */
case 103:
result += 11;
break;
case 104:
case 106:
result *= result;
break;
default:
result = 0;
}
return result;
} [/code]
这只是一段简单的switch语句,下面我们用一段c代码来描述汇编代码所要做得事情.
[code]code *jt[7] = {
loc_A, loc_def, loc_B, loc_C,
loc_D, loc_def, loc_D
};
int switch_eg_impl(int x)
{
unsigned xi = x - 100;
int result = x;
if (xi > 6)
goto loc_def;
/* Next goto is not legal C */
goto jt[xi];
loc_A: /* Case 100 */
result *= 13;
goto done;
loc_B: /* Case 102 */
result += 10;
/* Fall through */
loc_C: /* Case 103 */
result += 11;
goto done;
loc_D: /* Cases 104, 106 */
result *= result;
goto done;
loc_def: /* Default case*/
result = 0;
done:
return result;
} [/code]
看上面的代码就很清楚了,它会对传进来的值与100进行一个减法,然后再将这个值传进switch语句.
而真实的汇编代码是怎么样的呢,我们可以看看:
[code]switch_eg:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax //这边得到传进来的参数
leal -100(%eax), %edx //这边将得到的参数和100做差
cmpl $6, %edx //这边和6比较,如果大于6说明下面的条件没有满足的所以默认进入default
jbe .L11
.L2:
popl %ebp
xorl %eax, %eax
ret
.p2align 4,,7
.L11:
jmp *.L7(,%edx,4) //这边也就是我们上面伪码所描述的那个jt[xi]
.section .rodata
.align 4
.align 4
.L7: //这边就是所构造的跳转表.
.long .L3
.long .L2
.long .L4
.long .L5
.long .L6
.long .L2
.long .L6
.text
.L6: // loc_D
imull %eax, %eax
popl %ebp
.p2align 4,,6
ret
.L5: //loc_c
popl %ebp
movl $114, %eax
.p2align 4,,6
ret
.L4: //loc_B
popl %ebp
movl $123, %eax
.p2align 4,,4
ret
.L3: //loc_A
popl %ebp
movl $1300, %eax
.p2align 4,,4
ret[/code]