17

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

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

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

在上述情况下,永远不会调用ifsomefunc()返回TRUEthen 。anotherfunc()

从我目前所见,在德尔福中,这并不成立。而是,对于

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

然后,无论somefunc()返回什么,anotherfunc()都将被调用。

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

4

3 回答 3

24

文档链接在这里

布尔短路评估

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

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

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

在 {$B-} 状态下,编译器生成用于短路布尔表达式求值的代码,这意味着只要整个表达式的结果以从左到右的求值顺序变得明显,求值就会停止。

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


不幸的是,你在测试中有点搞混了。您的 Delphi 代码实际上与 C 代码完全不同。

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

在 Delphi 中,and运算符的优先级高于相等运算符=。这意味着您的 Delphi 代码相当于:

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

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

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

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

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

最后,你永远不应该在 Delphi 中False进行测试。True总是这样写代码:

if not somefunc() and anotherfunc() then 
于 2013-02-26T10:11:15.563 回答
5

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

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

那么你已经设置了BOOLEVAL ON

正如大卫指出的编译器首先评估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 OFFanotherfunc()永远不会被调用。

如果你想拥有相同的

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

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

于 2013-02-26T16:03:11.097 回答
0

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

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

这确保了调用每个函数,无论是打开还是关闭短 eval。

于 2017-04-09T00:29:50.097 回答