【编译器】if/switch之性能分析

同为条件分支语句,但if和switch的适用范围和性能略有不同。如果将if的适用范围表示为全集,那么switch的适用范围仅仅是它的一个真子集,因为switch只适用于整型表达式,例如int、char、short、long、enum和bool。

既然这样,为何还要switch?只是为了书写美观?当然不是。其实编译器像女朋友一样,默默地为我们做了很多事情。

1. 当case取值范围集中时

当case取值范围相对集中时,编译器会生成一张跳转表(Jump Table),每个表项是采取相应操作的地址。此时,switch花费的时间是常数时间,与case数量无关。

void fun(int i)
{
    switch (i)
    {
        case 0:
            i *= 2;
            break;
        case 2:
            i += 2;
            break;
        case 3:
            i += 3;
            break;
        case 4:
            i *= i;
            break;
        case 5:
            i += i;
            break;
        default:
            i = 0;
            break;
    }
}
fun:
    pushl    %ebp
    movl    %esp, %ebp
    cmpl    $5, 8(%ebp)    // 参数i放在%ebp + 8
    ja    .L2    // 无符号数比较
    movl    8(%ebp), %eax
    sall    $2, %eax    // 每个地址为4个字节
    addl    $.L8, %eax    // 基地址
    movl    (%eax), %eax
    jmp    *%eax
.L8:
    .long    .L3
    .long    .L2
    .long    .L4
    .long    .L5
    .long    .L6
    .long    .L7
.L3:
    sall    8(%ebp)
    jmp    .L1
.L4:
    addl    $2, 8(%ebp)
    jmp    .L1
.L5:
    addl    $3, 8(%ebp)
    jmp    .L1
.L6:
    movl    8(%ebp), %eax
    imull    8(%ebp), %eax
    movl    %eax, 8(%ebp)
    jmp    .L1
.L7:
    movl    8(%ebp), %eax
    addl    %eax, %eax
    movl    %eax, 8(%ebp)
    jmp    .L1
.L2:
    movl    $0, 8(%ebp)
    nop
.L1:
    popl    %ebp
    ret

从汇编代码可以看到所谓的跳转表,就是从标号L8开始的6个“长”字。每个字的值表示执行目标操作的地址,而L8则可被认为是基地址。

2. 当case取值范围很广时
此时,如果编译器生成跳转表,那么表项的数量会变得庞大,而且有用的表项只有少数几个,因此代价比较大。所以在这种情况下,编译器不会生成跳转表,而是像if...else一样翻译switch。
3. 当case数量很多且取值范围很广时

此时,编译器会重新排列case语句,并使用二分查找法加速查找过程。

综上,对于情况1和3,switch的效率明显高于if...else;而对于情况2,其实际效果和if...else一样。

PS:不同编译器为switch语句生成的汇编代码不尽相同,本文所用的编译器是gcc 4.5.2。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值