Delphi 中的布尔表达式求值顺序?
Boolean expression order of evaluation in Delphi?
if exp1 and exp2 and exp3 then
//something
在Delphi中求值的顺序exp1,exp2和exp3(当然都是Boolean
)是定义的还是随机的?
评价顺序只在Boolean Short-Circuit Evaluation is enabled. Then, as the documentation in 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.
对于第一个,您将打印 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-]
0040B17F E864EAFFFF call B
0040B184 837DE800 cmp dword ptr [ebp-],[=11=]
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
先执行,而是布尔表达式的顺序 - 操作数。
文档当然会指导您。
我发现,在更复杂的 if 语句中,即使是有经验的程序员在编写代码时,编译器也不会执行预期的操作,这通常是因为它们包括逻辑非以及混合布尔值与和或。记住优先级和关联规则并不总是那么容易。
我的建议是明确说明您想要什么,并在条款两边加上括号。编译器不会介意,当您或其他人审查代码时,它会清楚说明您的意图。
使用复合 if 语句将逻辑部分放在一起也可以帮助人们理解其含义。
例如:
if( ((pObjectRef<>nil) And (pObjecRef.Property=SomeValue)) Or
((pAlternateObject<>nil) And
((pAlternatObject.Property=AnotherValue) Or
(pAlternatObject.Property=YetAnotherValue))) ) then
begin
...
end
if exp1 and exp2 and exp3 then
//something
在Delphi中求值的顺序exp1,exp2和exp3(当然都是Boolean
)是定义的还是随机的?
评价顺序只在Boolean Short-Circuit Evaluation is enabled. Then, as the documentation in 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.
对于第一个,您将打印 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-]
0040B17F E864EAFFFF call B
0040B184 837DE800 cmp dword ptr [ebp-],[=11=]
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
先执行,而是布尔表达式的顺序 - 操作数。
文档当然会指导您。
我发现,在更复杂的 if 语句中,即使是有经验的程序员在编写代码时,编译器也不会执行预期的操作,这通常是因为它们包括逻辑非以及混合布尔值与和或。记住优先级和关联规则并不总是那么容易。
我的建议是明确说明您想要什么,并在条款两边加上括号。编译器不会介意,当您或其他人审查代码时,它会清楚说明您的意图。
使用复合 if 语句将逻辑部分放在一起也可以帮助人们理解其含义。
例如:
if( ((pObjectRef<>nil) And (pObjecRef.Property=SomeValue)) Or
((pAlternateObject<>nil) And
((pAlternatObject.Property=AnotherValue) Or
(pAlternatObject.Property=YetAnotherValue))) ) then
begin
...
end