Члены в операторе с оператором AND всегда проверяются в указанном порядке? - PullRequest
11 голосов
/ 15 марта 2012

Я хотел бы знать, может ли следующий код когда-либо завершиться с нарушением доступа или это безопасно.Первый член оператора с оператором AND всегда проверяется как первый или может быть (какой-то оптимизацией компилятора или чем-то еще) проверен второй как первый?

var
  Item: TSomething;

procedure DoSomething;
begin
  if Assigned(Item) and (Item.SomeProperty) then
    DoSomethingElse;
end;

Является ли приведенный выше код безопасным?*

Спасибо!

Ответы [ 3 ]

12 голосов
/ 15 марта 2012

Код безопасен, задан логическая оценка короткого замыкания активна:

В состоянии {$ B-} компилятор генерирует код для оценки логического выражения короткого замыкания, что означает, что оценка останавливается, как только результат всего выражения становится очевидным в порядке слева направо.

Это немного сбивает с толку, поскольку директива B (или BOOLEVAL с длинным именем) должна быть выключена, чтобы включить оценку короткого замыкания ВКЛ ...

См. Также Приоритет оператора .

4 голосов
/ 15 марта 2012

Это зависит от вашего типа Item.SomeProperty. Если это вариант или если перед ним есть вариант, который будет оценен, он будет оценен и вызовет AV.

Редактировать: забыть упомянуть обходной путь: Если SomeProperty имеет тип Variant, вы можете использовать

  if Assigned(Item) and StrToBool(Item.SomeProperty) then

Это действительно потратить некоторое время на преобразование переменной в String, а затем обратно в булево значение, но на практике это может удовлетворить все случаи истинности / ложности / небытия.

Ниже приведен тестовый пример для вас:

unit Unit4;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Generics.Collections;

type
  TTestObj = class
  public
    V : Variant;
    I : Integer;
  end;

  TForm4 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    btn3: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
    procedure btn3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    TOV : TTestObj;
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

procedure TForm4.btn1Click(Sender: TObject);
begin
  if Assigned(TOV) and (TOV.I = 10) then
    ShowMessage('You will never see this though no AV!');
end;

procedure TForm4.btn2Click(Sender: TObject);
begin
  if Assigned(TOV) and StrToBool(TOV.V) then
    ShowMessage('You will not see AV with StrToBool!');
  if Assigned(TOV) and TOV.V then
    ShowMessage('You will never see this but AVed!');
end;

procedure TForm4.btn3Click(Sender: TObject);
var
  V : Variant;
begin
  V := False;
  if Assigned(TOV) and V and (TOV.I = 10) then
    ShowMessage('You will see AV!');
end;

end.
3 голосов
/ 15 марта 2012

Безопасно называть условие, которое вы упомянули Посмотрите

У меня есть список строк, и я проверил два условия

    Strinlst : TStringlist; 

      Tester.pas.169: if ( (Assigned(Strinlst)) and(Strinlst.count<>6)) then
      0052A3CC 8BB3E4030000     mov esi,[ebx+$000003e4]
      0052A3D2 85F6             test esi,esi              //check if Strinlst is assigned
      0052A3D4 741F             jz $0052a3f5              //jump out if not true 
      0052A3D6 8BC6             mov eax,esi
      0052A3D8 8B10             mov edx,[eax]
      0052A3DA FF5214           call dword ptr [edx+$14]
      0052A3DD 83F806           cmp eax,$06               //compare the count
      0052A3E0 7413             jz $0052a3f5              //jump to the result

То же самое относится к условию в другом порядке

      Tester.pas.169: if ( (Strinlst.count<>6) and (Assigned(Strinlst)) ) then
      0052A3CB 8B83E4030000     mov eax,[ebx+$000003e4]
      0052A3D1 8B10             mov edx,[eax]
      0052A3D3 FF5214           call dword ptr [edx+$14]   //get the count
      0052A3D6 83F806           cmp eax,$06                //compare the count    
      0052A3D9 741B             jz $0052a3f6               //jump if not true  
      0052A3DB 83BBE403000000   cmp dword ptr [ebx+$000003e4],$00 //compare if Strinlst is assigned
      0052A3E2 7412             jz $0052a3f6              //jump if false

так что, конечно, порядок условий следует слева направо

...