2012-03-15 9 views
11

Aşağıdaki kodun erişim ihlali ile başarısız olup olmadığını veya güvenli olup olmadığını bilmek istiyorum. AND işlecinin ilk üyesi her zaman ilk olarak mı kontrol edilir, yoksa (bazı derleyici optimizasyonu veya bir şeyle) ikincisi ilk olarak mı kontrol edilir?VE operatöründeki ifadedeki üyeler her zaman verilen sırada kontrol ediliyor mu?

var 
    Item: TSomething; 

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

Yukarıdaki kod kesinlikle güvenli midir?

Teşekkürler!

+1

've' bir operatör değil, bir ifadedir: Eğer görmek için Aşağıda

bir test durumdur. Örneğiniz, boş belirteç istisnası '$ IFOPT B +' – OnTheFly

+0

@ user539484, zayıf terminolojim için üzgünüm :) '' ve 'operatörünün ifadesi olduğunu düşündüm. Onu tamir edeceğim. Yorumunuzda saklanan net cevap için teşekkürler. –

+1

niçin 'atanmışsa (öğe) o zaman öğ[email protected] ise item.someproperty ' –

cevap

12

kod boolean short-circuit evaluation aktif verilen güvenlidir: {$ B} durumda

derleyici değerlendirme sonucu olarak durur demektir kısa devre Boole ifade değerlendirme için, kodu üretir Tüm ifadenin soldan sağa değerlendirme sıralamasında belirginleşir.

O

da Operator Precedence bakınız ... direktif AÇIK kısa devre değerlendirmesini geçmek için kapalı bulunmalı B (uzun adıyla veya BOOLEVAL) olarak biraz kafa karıştırıcı.

+2

Bu yönerge asla ışığı hiç görmemeliydi. Yeryüzünde kim "dolu" boole değerlendirmesi ister? –

+0

Kısa devre ifadesi değerlendirmesinin daha sonra bir optimizasyon olarak eklendiğini ve tam değerlendirmeye bağlı olan mevcut kodu kırmamak için derleyici yönergesinin oluşturulduğunu tahmin ediyorum. – ain

+1

Muhtemelen haklısınız. Geriye dönük uyumluluk. :-) –

3

Onun belirtilen koşul göz Call güvenli

Bir StringList var ve

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 

Aynı diğer sırayla durum için de geçerli iki koşula karşı kontrol

 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 

kesinlikle koşulların sırası Soldan Sağa doğru izlenir

4

Item.SomeProperty türünüze bağlıdır. Varyant ise veya öncesinde değerlendirilecek bir varyant varsa, değerlendirilecek ve AV'ye neden olacaktır.

Düzenleme: SomeProperty Varyant türü ise,

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

O zamanlar boolean için dize değişkeni dönüştürmek için biraz zaman harcamak yok kullanabilirsiniz ancak kira azından yapabilirsiniz: geçici çözümü söz Forget Doğru/yanlış/varolmayan tüm vakaları tatmin eder.

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. 
+0

Bu çok önemli not için teşekkürler! Üyeler neyse ki Variant yazmamışlar. –

+0

@MartinReiner Üye bile Varyant değil, ifadede Varyant türü varsa dikkatli olun. Atanan (TOV) ve V ve (TOV.I = 10) ise ... V'nin varyantı da TOV.I'nin değerlendirilmesine ve AV'ye neden olmasına neden olacaktır. Bunu göstermek için cevabı güncelleyeceğim. – Justmade

+0

İlginç, bunu bilmiyordum – OnTheFly