Delphi中的布尔表达式求值顺序?
if exp1 and exp2 and exp3 then
//something
Delphi中exp1、exp2和exp3(当然都是Boolean)的求值顺序是定义的还是随机的?
回答
评估顺序仅在启用布尔短路评估时定义。然后,正如Complete Versus Short-Circuit Boolean Evaluation 中的文档所解释的那样,评估是从左到右的。
如果未启用布尔短路评估,则顺序未定义。以下代码演示了这一点:
{$APPTYPE CONSOLE}
function A: boolean;
begin
Result := True;
Write('A ');
end;
function B: string;
begin
Result := '';
Write('B ');
end;
function C: Integer;
begin
Result := 0;
Write('C ');
end;
begin
{$O+}
Writeln('short circuit on');
{$B-}
if A and (B = '') and (C = 0) then Writeln;
Writeln('short circuit off');
{$B+}
if A and (B = '') and (C = 0) then Writeln;
end.
对于第一个,您会得到 print A B C,对于第二个您会得到B A C。
这是为 Win32 编译的 - 为了使这个变得有趣,并把这个未定义的点带回家,让我们在 Win64 上运行它,我们A B C在这两种情况下都会得到它。
您可能会说:“好吧,但也许只是先调用了 B,但布尔表达式B = ''的计算是以正确的顺序计算的。” 让我们看一下执行的汇编代码:
if A and (B = '') and (C = 0) then Writeln;
0040B17C 8D45E8 lea eax,[ebp-$18]
0040B17F E864EAFFFF call B
0040B184 837DE800 cmp dword ptr [ebp-$18],$00
0040B188 0F94C3 setz bl
0040B18B E81CEAFFFF call A
0040B190 22D8 and bl,al
0040B192 E891EAFFFF call C
0040B197 85C0 test eax,eax
0040B199 0F94C0 setz al
0040B19C 22D8 and bl,al
不:
- 调用
B,比较'' - 调用
A,and它与字符串比较的结果 - 调用
C,比较0,and它与前一个的结果and
翻译成(按从左到右的顺序写):
((B = '') and A) and (C = 0)
附录:因为我在另一个答案中看到了这一点,并在评论中进行了讨论。括号不是强制操作数计算顺序的解决方案。您只能对操作进行分组,但编译器可能仍会决定首先评估正确的操作数。在上面的代码中,没有办法A B C仅仅因为编译器翻转了前两个操作数而放置任何括号。然而,它然后从左到右执行运算符,这很容易混淆 - 问题不是首先and执行第一个还是第二个,而是布尔表达式的顺序 - 操作数。