我正在阅读 this问题,这是公认的答案。我阅读了评论,但无法弄清楚产生优化的原因。
为什么在使用下面的代码时,汇编代码中会出现分支?
x >= start && x <= end
编辑:
为了清楚起见,我想了解接受的答案产生优化的原因。据我了解,这是编译器生成的汇编代码中存在的分支。我想了解为什么生成的代码中有一个分支。
最佳答案
请注意,链接的问题有一个根本不同的表达方式
x >= start && x++ <= end
这是根本不同的,因为这里的第二个子表达式有副作用。我会解释。
请注意 &&
是 short-circuit operator .这意味着如果 x >= start
评估为 false
,机器可以分支评估x <= end
.
更准确地说,当编译器为 x >= start && x <= end
发出指令时,它可以发出指令以在 x <= end
上分支什么时候x >= start
计算结果为假。
但是,我在上述陈述中强调了可以这个词的使用。这样做的原因是因为x <= end
没有副作用,因此编译器是否分支评估它并不重要。
但是,如果第二个表达式确实有副作用,编译器必须对其进行分支。自 &&
是短路运算符,在 a && b
中, 如果 b
有任何副作用,如果a
,它们绝不能被观察到评估为 false
;这是 C 和大多数(如果不是所有类 C 语言的话)短路的要求。
所以,特别是,当你看
define POINT_IN_RANGE_AND_INCREMENT(p, range)
(p <= range.end && p++ >= range.start)
注意第二个表达式 p++ >= range.start
有副作用。即,(后)递增 p
通过 1
.但只有在 p <= range.end
时才能观察到这种副作用评估为 true
.因此,编译器必须对 p++ >= range.start
的求值进行分支。如果p <= range.end
计算结果为假。
这导致分支的原因是因为机器计算该表达式时,它使用了 if p <= range.end
的事实。 评估为 false
, 然后它会自动知道整个表达式的计算结果为 false
因此它不应该评估p++ >= range.start
因为它有副作用。因此,它必须分支计算表达式的第二部分。所以在汇编中:
Ltmp1301:
ldr r1, [sp, #172] @ 4-byte Reload
ldr r1, [r1]
cmp r0, r1
bls LBB44_32
mov r6, r0 @ if the result of the compare is false
b LBB44_33 @ branch over evaluating the second expression
@ to avoid the side effects of p++
LBB44_32:
ldr r1, [sp, #188] @ 4-byte Reload
adds r6, r0, #1
Ltmp1302:
ldr r1, [r1]
cmp r0, r1
bhs LBB44_36
深表感激Oli Charlesworth有见地的评论。
关于c++ - 为什么在比较范围内的数字时,汇编代码中会出现分支?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17114371/