利用短路减少冗余的运算或者判断
【说明】 在逻辑表达式中,利用逻辑操作符“&&”和“||”的短路求值或者最小化求值策略,合理地对子表达式排序,尽可能减少不必要的表达式被求值。
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();
}
}
说明:根据语句的执行频次(即高概率发生的语句),放在“||”语句的左侧,从而减少实际运行时的指令数。
父主题: 表达式