首页 > 解决方案 > Delphi中评估的布尔表达式顺序?

问题描述

if exp1 and exp2 and exp3 then
    //something

在Delphi中,exp1、exp2和exp3(当然都是Boolean)的求值顺序是定义的还是随机的?

标签: delphibooleanpascallogical-operators

解决方案


仅当启用布尔短路评估时才定义评估顺序。然后,正如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 编译的——为了让这个更辣,并带回家这是未定义的一点,让我们A B C在两种情况下都得到的 Win64 上运行它。

您可能会说:“好的,但也许首先调用了 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,比较''
  • 调用Aand它与字符串比较的结果
  • 调用C, 比较0,and它与前面的结果and

转换为(按从左到右的顺序编写):

((B = '') and A) and (C = 0)

附录:因为我在另一个答案中看到了这一点并在评论中进行了讨论。括号不是强制操作数求值顺序的解决方案。您只能对操作进行分组,但编译器仍可能决定首先评估正确的操作数。在上面的代码中,无法A B C简单地放置任何括号,因为编译器翻转了前两个操作数。然后它从左到右执行运算符,这很容易混淆 - 问题不在于第一个还是第二个and是首先执行的,而是布尔表达式的顺序 - 操作数。


推荐阅读