Delphi中if语句的评估顺序

Posted

技术标签:

【中文标题】Delphi中if语句的评估顺序【英文标题】:Evaluation order for if statement in Delphi 【发布时间】:2015-03-13 13:24:54 【问题描述】:

我知道以下函数语句的答案:

if (TestFunc1()) and (TestFunc2()) then
    DoSomething();

这个问题很好地回答了这个问题: Delphi 'AND' evaluation with 2 conditions

例如,您可以通过调试或记录来轻松测试这一点。但是在这个例子中,你将如何测试编译器正在做什么(比如 ech 参数被定义为布尔值):

if (SomeObj1.bNaughtyGlobal1) and (SomeObj2.bNaughtyGlobal2) then
    DoSomething();

是的,我知道理想情况下参数会隐藏在访问器函数后面...但是有没有聪明的方法来测试 SomeObj2 是否正在被访问?

【问题讨论】:

“测试 SomeObj2 是否被访问”是什么意思?当您阅读 SomeObj2.bNaughtyGlobal2 时会发生什么,它将获取 SomeObj2 应该是的地址,添加 bNaughtyGlobal2 应该是的偏移量并在该地址获取该值。 是的,这正是我的意思。在这个问题之后几分钟你自己的答案是一个不错的答案,谢谢。 是什么让你认为对象的属性是全局的? @Craig: “全局”,因为该属性在对象的类定义中被定义为公共。但并不严格相关,因为变量可能是本地的。 【参考方案1】:

答案与您链接到的问题相同。作为and 的操作数的表达式是函数调用还是变量并不重要。如果满足以下条件,将评估第二个操作数:

    未启用短路评估,或 短路评估已启用,第一个操作数评估为真。

默认编译器选项启用了短路评估,我不知道在任何情况下更改它是有意义的。因此,假设您在启用短路评估的情况下进行编译,那么当且仅当第一个操作数的评估结果为 true 时,才会评估第二个操作数。

如果您热衷于在调试器下看到这一点,请尝试使用或不使用短路评估的程序:

$APPTYPE CONSOLE

type 
  TMyRecord = record
    foo: Integer;
  end;
  PMyRecord = ^TMyRecord;

var 
  P: PMyRecord = nil;
begin
  if Assigned(P) and (P.foo=1) then 
    Writeln;
end.

如果没有短路,P.foo 的评估是运行时错误。通过短路评估,没有运行时错误。

确实,这个具体示例是应启用短路评估的最佳原因之一。否则这样的代码会过于冗长。

【讨论】:

是的,我已启用短路编译选项(项目 > 选项 > 编译器 > 完整布尔评估 = 关闭)。我知道编译应该是一样的,但是使用函数你可以很容易地测试编译器做了什么。很想知道是否有一种聪明的方法可以用参数证明这一点。 是的,谢谢你的例子。尝试了两个编译器选项,它按预期工作或失败。我做了一个小的修改,使示例更加清晰(希望你也这么认为)。短路编译器选项绝对值得推荐……现在我理解多了! 这个例子需要一些小的调整才能在 Delphi7 中编译。记录“结束”后需要一个分号。不支持变量初始化 (n: Integer = 5;)。再次感谢。 感谢分号更正。变量初始化很好。根据我的代码,它必须是全球性的。问题中的代码是一个完整的程序记住。所以 P 是一个全局变量。将其粘贴到 .dpr 文件中就可以了。 啊,是的,P 是全局的。我将它作为函数的局部变量进行了测试。再次感谢。【参考方案2】:

设置断点

if (SomeObj1.bNaughtyGlobal1) and (SomeObj2.bNaughtyGlobal2) then

现在运行你的程序到断点。 打开 CPU 窗口(查看->调试窗口->CPU)并逐步执行处理器指令。 在那里您将看到跳转指令,并且您还将看到如果 SomeObj1.bNaughtyGlobal1 为 false 则不会评估其他任何内容,而不是您的 SomeObj2 对象。

【讨论】:

刚刚试了一下,效果很好!不太熟悉汇编程序,但我能够看到两个“cmp”语句,第二个被跳过了。感谢您的提示! @AlainD 有趣的是,如果您关闭短路评估,您将看到不同的机器代码。 是的,很好看。我可以看到,当短路关闭时,两个“cmp”语句将在“jmp”被命中之前运行。【参考方案3】:

设置SomeObj1.bNaughtyGlobal1 := FalseSomeObj2 := nil。如果编译器行为不端并评估 and 表达式的两边,那么当您的程序尝试从空引用中读取 bNaughtyGlobal2 值时,您将遇到访问冲突。

【讨论】:

很好,实际上是在发布问题大约 30 分钟后想到的。

以上是关于Delphi中if语句的评估顺序的主要内容,如果未能解决你的问题,请参考以下文章

评估布尔语句的顺序是啥? [复制]

如何在 freemarker 中评估 if 语句?

如何在javascript中评估语句if [重复]

在 C++ 中如何评估 if 语句?

在 if 语句中评估单个字符:C++

这个 if 语句如何评估为真?