【问题标题】:Delphi 'AND' evaluation with 2 conditionsDelphi 'AND' 评估有 2 个条件
【发布时间】:2013-02-26 08:15:54
【问题描述】:

我不得不为我最近正在做的一项合同工作选择 Delphi,我希望有人澄清的一件事是在条件语句中执行逻辑,例如 if

我来自 C/C++ 和这些语言的背景,一旦知道 if 语句失败,其余的逻辑就不会执行。例如:

if (somefunc() == FALSE && anotherfunc() == TRUE)

在上述情况下,如果somefunc() 返回TRUE,则永远不会调用anotherfunc()

就我目前所见,在 Delphi 中,这并不成立。相反,对于

if (somefunc() = False and anotherfunc() = True) then

那么,无论somefunc() 返回什么,anotherfunc() 都会被调用。

我已经阅读了各种 Delphi 书籍,并重读了一些条件章节,但在任何地方都找不到关于这种行为的提及。谁能指出我在 Delphi 或 Pascal 的某个地方声明了这种行为?

【问题讨论】:

  • 查看en.wikipedia.org/wiki/Short-circuit_evaluation - “允许但不需要短路”。
  • 您不需要编写布尔状态,即= False= True。相反,您可以使用not 运算符来检查是否为假,方法是不包括not 部分您的 if 语句以相反的方式工作,例如 true 而不是 false。
  • 根据你打算如何解释你的 Delphi 代码, anotherfunc 应该 在 somefunc 返回 false 时被调用,但你说这是个问题。
  • 对不起,上面的示例代码是错误的。您显然错过了一些括号,因此编译器将尝试评估“FALSE 和 anotherfunc()”,并且不知道如何处理“somefunc()”和“True”。无论如何,我明白你的观点并理解你的问题,只是告诉我这件事让我感觉更好。

标签: delphi


【解决方案1】:

documentation link is here:

布尔短路评估

类型开关 语法 {$B+} 或 {$B-} {$BOOLEVAL ON} 或 {$BOOLEVAL OFF} 默认 {$B-} {$BOOLEVAL OFF} 范围本地

$B 指令在 Delphi 的两种不同模型之间切换 andor 布尔运算符的代码生成。

在 {$B+} 状态下,编译器生成完整布尔值的代码 表达式评估。这意味着布尔值的每个操作数 由 and 和 or 运算符构建的表达式保证为 评估,即使整个表达式的结果已经 已知。

在 {$B-} 状态下,编译器生成短路代码 布尔表达式评估,这意味着评估停止为 一旦整个表达式的结果在 left to 中变得明显 正确的评估顺序。

如您所见,默认选项用于短路评估。


很遗憾,您的测试有点搞混了。您的 Delphi 代码实际上与 C 代码完全不同。

if (somefunc() == FALSE && anotherfunc() == TRUE)      // C code
if (somefunc() = False and anotherfunc() = True) then   // Delphi code

在 Delphi 中,and 运算符具有 higher precedence,而不是相等运算符 =。这意味着您的 Delphi 代码相当于:

if (somefunc() = (True and anotherfunc()) = True) then

但在 C 和 C++ 中,优先级是相反的。所以&&==lower precedence。因此,无论短路评估如何,您问题中的 Delphi 和 C++ if 语句在逻辑上都是不同的。

我很确定你真的打算像这样编写你的 Delphi 代码:

if ((somefunc() = False) and (anotherfunc() = True)) then 

这将提供与您的 C++ 代码相同的逻辑,并且由于短路评估,您会看到相同的行为。

最后,永远不要在 Delphi 中测试 FalseTrue。总是这样写代码:

if not somefunc() and anotherfunc() then 

【讨论】:

  • +1 仅用于您的最后一个陈述,我希望我可以再做一个来解释潜在问题​​。
  • 我经常在 Delphi 和 VS 之间切换,这总是让我很兴奋……我要么在不需要时在 C# 中添加括号,要么在 Delphi 中忘记它们,然后立即给自己一记耳光面对这样做。
  • @J... 是的,我也一直在为此苦苦挣扎。我总是在我的 C# 代码中加上额外的括号,因为我永远记不起运算符的优先级。
  • 很好的答案。如果您考虑一下,somebool and anotherbool 是一个有效的布尔语句,但 somebool and somevalue = something 并不会迫使您在布尔评估周围添加括号。
  • @nrjohnstone 好吧,if 需要一个计算结果为 Boolean 的表达式。如果您有一个返回Boolean 的函数,那么它已经是一个计算结果为Boolean 的表达式。测试TrueFalse 显然是多余的。正如您所发现的那样,这样做会导致您进入支架地狱。您可能来自不包含真正布尔类型的旧版本 C 的背景。德尔福是不同的。
【解决方案2】:

如果您的函数 anotherfunc() 被此代码调用

if (somefunc() = False and anotherfunc() = True) then

那么你已经设置了BOOLEVAL ON

正如 David 指出的那样,编译器首先评估 False and anotherfunc()

BOOLEVAL OFF 模式下,编译器知道False and AnyBoolState 将导致False,因此不会调用anotherfunc()(实际上它永远不会被调用)。

作为一个简单的测试,我扩展了jachaguate程序以显示您的表情

program AndEvaluation;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

function FalseFunc( const AName : string ) : Boolean;
begin
  Write( AName, '(False)', '-' );
  Result := False;
end;

function TrueFunc( const AName : string ) : Boolean;
begin
  Write( AName, '(True)', '-' );
  Result := True;
end;

begin
  try

    // (somefunc() = False and anotherfunc() = True)
    //
    // in this testcase translated to:
    //
    // somefunc()    => FalseFunc( 'First' )
    // False         => FalseFunc( 'Second' )
    // anotherfunc() => TrueFunc( 'Third' )
    // True          => TrueFunc( 'Fourth' )

{$B+}
    Writeln( 'BOOLEVAL ON' );
    if ( FalseFunc( 'First' ) = FalseFunc( 'Second' ) and TrueFunc( 'Third' ) = TrueFunc( 'Fourth' ) )
    then
      Writeln( 'True' )
    else
      Writeln( 'False' );
{$B-}
    Writeln( 'BOOLEVAL OFF' );
    if ( FalseFunc( 'First' ) = FalseFunc( 'Second' ) and TrueFunc( 'Third' ) = TrueFunc( 'Fourth' ) )
    then
      Writeln( 'True' )
    else
      Writeln( 'False' );

  except
    on E : Exception do
      Writeln( E.ClassName, ': ', E.Message );
  end;

  ReadLn;

end.

现在让我们看看结果

BOOLEVAL ON
Second(False)-Third(True)-First(False)-Fourth(True)-True

BOOLEVAL OFF
First(False)-Second(False)-Fourth(True)-True

正如输出所解释的那样,拥有BOOLEVAL ON 你的anotherfunc() 将被调用 somefunc() 被调用之前。

使用BOOLEVAL OFF,您的anotherfunc()永远不会被调用。

如果你想拥有一样的

if (somefunc() == FALSE && anotherfunc() == FALSE)

你必须这样翻译

if ( somefunc() = False ) and ( anotherfunc() = False ) then

更好更短的方式

if not somefunc() and not anotherfunc() then

甚至更短

if not( somefunc() or anotherfunc() ) then

但为了避免每次必须设置 BOOLEVAL OFF 时都调用 anotherfunc()

【讨论】:

  • +1 这个,以及问题中“即使 somefunc 返回 False”的存在告诉我,提问者正在运行的实际代码是 if (somefunc() = True and anotherfunc() = True) then
  • @DavidHeffernan 是的,如果设置了BOOLEVAL OFF,那将是唯一的可能性:o) 让我们等待 OP 的反应......
  • 实际上很难想象提问者已将 BOOLEVAL 设置为 ON。
【解决方案3】:

为避免不调用函数,您可以这样做:

  bool_somefunc := (somefunc() = 42);
  bool_anotherfunc := (anotherfunc() = 17);
  if ( (bool_somefunc = False) and (bool_anotherfunc = True) ) then

这确保每个函数都被称为短 eval 开启或关闭。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多