之间最有效的选择是什么:
if(myConditionA){
if (myConditionB){
if (myConditionC){
//do something
}
}
}
和
if(myConditionA && myConditionB && myConditionC){
//do something
}
最佳选择是什么?为什么?这取决于语言吗?
编辑:这不是关于代码质量的问题。
答案 0 :(得分:4)
当你尝试它时发生了什么,为什么你会期望编译器产生什么有任何区别?你的算法在两者之间没有区别。
unsigned int one ( unsigned int myConditionA, unsigned int myConditionB, unsigned int myConditionC )
{
if(myConditionA){
if (myConditionB){
if (myConditionC){
//do something
return(1);
}
}
}
return(0);
}
unsigned int two ( unsigned int myConditionA, unsigned int myConditionB, unsigned int myConditionC )
{
if(myConditionA && myConditionB && myConditionC){
//do something
return(1);
}
return(0);
}
00000000 <one>:
0: e3510000 cmp r1, #0
4: 13520000 cmpne r2, #0
8: 13a02001 movne r2, #1
c: 03a02000 moveq r2, #0
10: e3500000 cmp r0, #0
14: 03a00000 moveq r0, #0
18: 12020001 andne r0, r2, #1
1c: e12fff1e bx lr
00000020 <two>:
20: e3510000 cmp r1, #0
24: 13520000 cmpne r2, #0
28: 13a02001 movne r2, #1
2c: 03a02000 moveq r2, #0
30: e3500000 cmp r0, #0
34: 03a00000 moveq r0, #0
38: 12020001 andne r0, r2, #1
3c: e12fff1e bx lr
好吧,好吧这很难看,但仅仅是因为我编写测试的方法,如果这些是其中之一,但两者都没有,那么编译器就会清楚地生成相同的代码。因此,对此进行测量性能测试可能会显示出差异,如果您能够看到它,但这是一个糟糕的测试。
00000000 <two>:
0: 10800006 beqz $4,1c <two+0x1c>
4: 00801025 move $2,$4
8: 10a00003 beqz $5,18 <two+0x18>
c: 00000000 nop
10: 03e00008 jr $31
14: 0006102b sltu $2,$0,$6
18: 00001025 move $2,$0
1c: 03e00008 jr $31
20: 00000000 nop
00000024 <one>:
24: 08000000 j 0 <two>
28: 00000000 nop
另一个指令集。
00000000 <_one>:
0: 1d80 0002 mov 2(sp), r0
4: 0308 beq 16 <_one+0x16>
6: 0bf6 0004 tst 4(sp)
a: 0306 beq 18 <_one+0x18>
c: 15c0 0001 mov $1, r0
10: 0bf6 0006 tst 6(sp)
14: 0301 beq 18 <_one+0x18>
16: 0087 rts pc
18: 0a00 clr r0
1a: 0087 rts pc
0000001c <_two>:
1c: 1d80 0002 mov 2(sp), r0
20: 0308 beq 32 <_two+0x16>
22: 0bf6 0004 tst 4(sp)
26: 0306 beq 34 <_two+0x18>
28: 15c0 0001 mov $1, r0
2c: 0bf6 0006 tst 6(sp)
30: 0301 beq 34 <_two+0x18>
32: 0087 rts pc
34: 0a00 clr r0
36: 0087 rts pc
不同的编译器
00000000 <one>:
0: e3510000 cmp r1, #0
4: 13a01001 movne r1, #1
8: e3500000 cmp r0, #0
c: 13a00001 movne r0, #1
10: e3520000 cmp r2, #0
14: e0000001 and r0, r0, r1
18: 13a02001 movne r2, #1
1c: e0000002 and r0, r0, r2
20: e12fff1e bx lr
00000024 <two>:
24: e3510000 cmp r1, #0
28: 13a01001 movne r1, #1
2c: e3500000 cmp r0, #0
30: 13a00001 movne r0, #1
34: e3520000 cmp r2, #0
38: e0000001 and r0, r0, r1
3c: 13a02001 movne r2, #1
40: e0000002 and r0, r0, r2
44: e12fff1e bx lr
另一个目标与其他编译器
00000000 <one>:
0: 27bdfff8 addiu $29,$29,-8
4: afbe0004 sw $30,4($29)
8: 03a0f025 move $30,$29
c: 0005082b sltu $1,$0,$5
10: 0004102b sltu $2,$0,$4
14: 00410824 and $1,$2,$1
18: 0006102b sltu $2,$0,$6
1c: 00221024 and $2,$1,$2
20: 03c0e825 move $29,$30
24: 8fbe0004 lw $30,4($29)
28: 03e00008 jr $31
2c: 27bd0008 addiu $29,$29,8
00000030 <two>:
30: 27bdfff8 addiu $29,$29,-8
34: afbe0004 sw $30,4($29)
38: 03a0f025 move $30,$29
3c: 0005082b sltu $1,$0,$5
40: 0004102b sltu $2,$0,$4
44: 00410824 and $1,$2,$1
48: 0006102b sltu $2,$0,$6
4c: 00221024 and $2,$1,$2
50: 03c0e825 move $29,$30
54: 8fbe0004 lw $30,4($29)
58: 03e00008 jr $31
5c: 27bd0008 addiu $29,$29,8
即使没有优化我也得到了同样的结果。两者之间没有区别,为什么编译器会产生差异,这可能是性能差异?
答案 1 :(得分:2)
如果您有类似的东西,最好的方法是避免使用箭头代码:
if (!aggergateCondition())
return;
// do something
您还可以将所有条件抛入另一个函数并使用它:
&&
它使您的代码清晰可读,减少缩进量,使结构变平。
表现更好的方法理论上是带有&&
语句的表单。为什么?因为它不分支而且很懒惰。 if语句也有点懒惰,但它们分支。
但这不一定是必须的。您必须考虑branch prediction,这可能会忽略其中一些if语句,并且可能会更频繁地在if
运算符处中断(只省略一个if
语句会更容易)。也许编译器可能会进行一些优化,这可能会导致这两种{{1}}情况都会产生相同的汇编或字节代码。
所以基本上 - 很难说哪个具有更好的性能,因为在编译器优化甚至CPU架构的幕后发生的魔力。
如果您需要一些过早的优化教程,我建议您this预订:)
答案 2 :(得分:1)
编译代码中的短路&&
和嵌套if
之间几乎没有区别,但仍有一些方法可以优化这种情况。这取决于每种情况的可能性。这可以通过配置文件引导优化来确定,或者您可以尝试并凭经验确定统计信息。
如果每个布尔条件具有相同的近似似然,那么顺序并不重要;但是,如果一个或多个人有更大的机会被假,那么他们应该被命令从最可能是假的,最有可能是真的。如果所有这些都很可能是真的(将所有概率乘以真收率&gt; = 0.5)那么使用按位&
运算符而不是逻辑&&
运算符将消除通常不必要的分支条件
总会有例外情况,比如其中一个条件是调用相对较慢的函数(而不仅仅是存储的布尔值),例如if ((*d == *s) && !strcmp(d,s)){ ... }