2012-04-09 163 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;