Являются ли члены в заявлении с оператором AND всегда проверены в данном порядке?
Я хотел бы знать, может ли следующий код когда-либо провалиться с нарушением прав доступа или если он безопасен. Является ли первый член оператора с оператором AND всегда проверяемым как первым, так и может быть (с помощью некоторой оптимизации компилятора или что-то в этом роде) проверил второй как первый?
var
Item: TSomething;
procedure DoSomething;
begin
if Assigned(Item) and (Item.SomeProperty) then
DoSomethingElse;
end;
Является ли код выше определенно безопасным?
Спасибо!
Ответы
Ответ 1
Код безопасен, если булевая оценка короткого замыкания активна:
В состоянии {$ B-} компилятор генерирует код для вычисления Boolean выражения короткого замыкания, что означает, что оценка останавливается, как только результат всего выражения становится очевидным в порядке слева и справа.
Это немного запутанно, так как директива B
(или BOOLEVAL
с длинным именем) должна быть отключена, чтобы включить оценку короткого замыкания ON...
См. также Приоритет оператора.
Ответ 2
Это зависит от типа 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
Безопасно называть указанное вами условие
Посмотрите
У меня есть строковый список, и я проверил два условия
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
так что, конечно, порядок условий соблюдается слева направо