delphi - 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 编译的——为了让这个更辣,并带回家这是未定义的一点,让我们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
,比较''
- 调用
A
,and
它与字符串比较的结果 - 调用
C
, 比较0
,and
它与前面的结果and
转换为(按从左到右的顺序编写):
((B = '') and A) and (C = 0)
附录:因为我在另一个答案中看到了这一点并在评论中进行了讨论。括号不是强制操作数求值顺序的解决方案。您只能对操作进行分组,但编译器仍可能决定首先评估正确的操作数。在上面的代码中,无法A B C
简单地放置任何括号,因为编译器翻转了前两个操作数。然后它从左到右执行运算符,这很容易混淆 - 问题不在于第一个还是第二个and
是首先执行的,而是布尔表达式的顺序 - 操作数。
推荐阅读
- android - Inkscape SVG 到 Android 矢量
- angular - 如果我将数据发送到 NativeScript 中的服务器,有没有办法刷新视图?
- c++ - codecvt_utf8_utf16 可以和 wfstream 一起使用吗?
- neo4j - 如何在 neo4j 的 FOREACH 子句中定义变量,如何查找两个节点的公共属性数
- laravel - Laravel 5 上的表单验证
- c - 带条件格式的 Printf
- python - Pandas Dataframe 问题:应用函数添加带有结果的新列
- swift - 设置布局的理想场所
- python - 具有多个条件的 Groupby 函数
- android - I/HwPointEventFilter:不支持 AFT,因为没有配置