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

利用短路减少冗余的运算或者判断

【说明】 在逻辑表达式中,利用逻辑操作符“&&”和“||”的短路求值或者最小化求值策略,合理地对子表达式排序,尽可能减少不必要的表达式被求值。

C/C++语言标准中,“&&”的右运算数仅当左运算数不等于0时才求值,“||”的右运算数仅当左运算数等于0时才求值。

求值不仅包括表达式值计算,还包括表达式的副作用,比如volatie对象读写、修改(写入)对象、调用库I/O函数。

值得注意的是,“operator &&”和“operator ||”的短路求值性质,对重载不适用。

在C/C++中,下面的表达是等价的:
if (simple_expression_a && expensive_expression_b) {
    // do something
}
if (simple_expression_a) {
    if (expensive_expression_b) {
        // do something
    }
}

【原理】 C/C++对逻辑运算符的说明(短路求值):

  • 针对“lhs && rhs”的逻辑与表达式,在“lhs”求值后有一个顺序点(sequence point),若“lhs”的结果等于零,则完全不求值“rhs”;
  • 针对“lhs || rhs”的逻辑与表达式,在“lhs”求值后有一个顺序点(sequence point),若“lhs”的结果不等于零,则完全不求值“rhs”;

【注意事项】 不涉及

【案例】

优化前

假设Judge(b)的可能性更高:
void Func(int32_t a, int32_t b) 
{
    if ((Check(a)) || (Judge(b))) {
        DoSomething();
    }
}
针对上述代码生成的汇编指令如下,其中,针对Check(a)和Judge(b)表达式生成指令存在连续执行的顺序代码:
Func(int, int):
        push    {r4, lr}
        mov     r4, r1
        bl      Check(int)
        cmp     r0, #0
        bne     .L3
        mov     r0, r4
        bl      Judge(int)
        cmp     r0, #0
        popeq   {r4, pc}
.L3:
        pop     {r4, lr}
        b       DoSomething()
优化后
void Func(int32_t a, int32_t b) 
{
    if ((Judge(b)) || (Check(a))) {
        DoSomething();
    }
}

说明:根据语句的执行频次(即高概率发生的语句),放在“||”语句的左侧,从而减少实际运行时的指令数。