鲲鹏社区首页
中文
注册
开发者
我要评分
获取效率
正确性
完整性
易理解
在线提单
论坛求助

小范围紧凑的判断使用switch语句替代if-else

【说明】 使用Switch/case语句,减少不必要的if语句的多次条件判断。

【原理】 由于switch...case会生成一个跳转表来指示实际的case分支的地址,跳转表的索引号等于switch变量的值,因此switch...case不用像if...else if那样遍历条件分支直到命中条件,从而提升执行效率。

【注意事项】 实际软件编码的过程中,更关键的问题是如何对于逻辑判断和跳转表进行选择:对于已经明确应使用跳表的场景,又因为判决条件的逻辑导致无法采用switch...case的方式实现,则需要通过代码实现跳转表。

【案例】

优化前
int Func(int choice) 
{
    int ret = GetA();

    if(choice == 1) {
        ret = ret + GetB(); 
    } 
    if (choice == 2) {
        ret = ret + GetC();
    } 
    if (choice == 3) {
        ret = ret + GetD();
    } 
    if (choice == 4) {
        ret = ret + GetE();
    } 
    if (choice == 5) {
        ret = ret + GetF();
    } 
    if (choice == 6) {
        ret = ret + GetG();
    } else {
        ret = GetH();
    }
    return ret;
}
对应的汇编指令如下,当choice的取值大于等于6时,会依次与1、2、3、4、5、6比较:
Func(int):
        push    {r4, r5, r6, lr}
        mov     r4, r0
        bl      GetA()
        cmp     r4, #1
        beq     .L13
        cmp     r4, #2
        beq     .L14
        cmp     r4, #3
        beq     .L15
        cmp     r4, #4
        bne     .L7
        bl      GetE()
.L6:
        pop     {r4, r5, r6, lr}
        b       GetH()
.L15:
        bl      GetD()
        pop     {r4, r5, r6, lr}
        b       GetH()
.L14:
        bl      GetC()
        pop     {r4, r5, r6, lr}
        b       GetH()
.L13:
        bl      GetB()
        pop     {r4, r5, r6, lr}
        b       GetH()
.L7:
        cmp     r4, #5
        bne     .L3
        bl      GetF()
        pop     {r4, r5, r6, lr}
        b       GetH()
.L3:
        cmp     r4, #6
        bne     .L6
        mov     r5, r0
        bl      GetG()
        add     r0, r5, r0
        pop     {r4, r5, r6, pc}
优化后
int Func(int choice) 
{
    int ret = GetA();
    
    switch(choice){
        case 1:
            ret = ret + GetB();
            break;
        case 2:
            ret = ret + GetC();
            break;
        case 3:
            ret = ret + GetD();
            break;
        case 4:
            ret = ret + GetE();
            break;
        case 5:
            ret = ret + GetF();
            break;
        case 6:
            ret = ret + GetG();
            break;
        default:
            ret = GetH();
    }
    return ret;
}
对应的汇编代码:
Func(int):
        push    {r4, r5, r6, lr}
        mov     r4, r0
        bl      GetA()
        mov     r5, r0
        sub     r0, r4, #1
        cmp     r0, #5
        ldrls   pc, [pc, r0, asl #2]
        b       .L2
        .word   .L3
        .word   .L5
        .word   .L6
        .word   .L7
        .word   .L8
        .word   .L9
.L9:
        bl      GetG()
        add     r0, r5, r0
        pop     {r4, r5, r6, pc}
.L3:
        bl      GetB()
        add     r0, r5, r0
        pop     {r4, r5, r6, pc}
.L5:
        bl      GetC()
        add     r0, r5, r0
        pop     {r4, r5, r6, pc}
.L6:
        bl      GetD()
        add     r0, r5, r0
        pop     {r4, r5, r6, pc}
.L7:
        bl      GetE()
        add     r0, r5, r0
        pop     {r4, r5, r6, pc}
.L8:
        bl      GetF()
        add     r0, r5, r0
        pop     {r4, r5, r6, pc}
.L2:
        pop     {r4, r5, r6, lr}
        b       GetH()

需要注意的是,编译器也会针对条件判断逻辑进行优化,针对部分场景下的if语句,可能在编译阶段被优化成跳转表的实现(即switch的方式)。