2012-04-09 201 views
3

我有下面的代碼:德爾福結構

type THead = packed record 
    znmpc: byte; 
    znmpcch: array [0..1] of char; 
    znc, zneispr, zkpd, zkps, nd: byte; 
    zb9, zb10, zb11, zb12, zb13, zb14, zb15: byte; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    db: ^THead; 
    a: array [0..9] of byte; 
begin 
    a[7] := 9; 
    db := @a; 
    ShowMessage(IntToStr(db.nd)); 
end; 

這段代碼安全嗎?我擔心下一件事:struct的大小超過了緩衝區的大小,我對此感到恐懼。 nd之後的struct成員的值對我來說沒有任何意義。我想知道這個代碼在某些情況下是否會拋出異常,如果是這樣的話?

+0

在你的情況下,它是完全安全的。 – 2012-04-09 10:36:20

回答

6

我想如果你仔細處理它是完全安全的。但是你需要確定你不會忘記你不能訪問zb11..zb15。另外,回想一下,char在Delphi 2009之前是1個字節,在Delphi 2009及更高版本中是2個字節。另外,也許值得做記錄packed(不要以爲你在這種情況下需要這樣做,但從容地顯式表達是絕對不會錯的)?最後,當然你必須小心,這樣陣列不會超出範圍!

+0

應該打包,cos在'znmpc'上,他會得到3個字節的對齊不匹配(默認對齊大小)。 – Kromster 2012-04-09 09:00:19

+0

我使用德爾福7,我做記錄包裝。我的恐懼基於以下想法:打包記錄的大小超過數組大小。最有可能涉及位於數組中的內存轉換。突然陣列將位於我可用的內存末尾? – Xaver 2012-04-09 09:04:30

2

我想讀取db.nd是好的。您將訪問堆棧中不屬於您的某個地方。但是寫一些東西給這個變量會導致災難性的失敗,我們不知道。

此外,如果超過你的邊界太多,你可以訪問衝突閱讀過:

procedure TForm2.Button1Click(Sender: TObject); 
var 
    db: THead; 
    p: PByte; 
begin 
    db.nd := 9; 
    p := @db; 

    ShowMessage(IntToStr(p[7])); // shows 9 
    ShowMessage(IntToStr(p[700])); // shows 182 for me? 
    ShowMessage(IntToStr(p[70000])); // shows 0 
    ShowMessage(IntToStr(p[700000])); // access violation! 
end; 

它是利用工會組織更安全:

type 
    THead = packed record 
    znmpc: byte; 
    znmpcch: array [0..1] of AnsiChar; 
    znc, zneispr, zkpd, zkps, nd: byte; 
    zb9, zb10, zb11, zb12, zb13, zb14, zb15: byte; 
    end; 

    THeaderUnion = packed record 
    case Integer of 
     0: (Head: THead); 
     1: (ByteArray: Array[0.. sizeof(THead)-1] of Byte); 
    end; 

procedure TForm1.Button1Click(Sender: TObject); 
Var 
    db: THeaderUnion; 
begin 
db.ByteArray[7] := 9; 
ShowMessage(IntToStr(db.Head.nd)); 
end;