2011-05-06 70 views
3

這將(希望)得到解決蠻快的,這是我的問題:中SizeOf動態結構

我有一個結構

PMacro = ^TMacro; 
    TMacro = class 
    Hotkey: Integer; 
    Command: String; 
    CTRLMode: boolean; 
    RepeatInterval: integer; 

    constructor Create(Hotkey: Integer; Command: String; CTRLMode: boolean; RepeatInterval: integer); overload; 
    constructor Create; overload; 
    procedure Execute; 
    end; 

,我需要得到它的大小(通過TFileStream的保存) 。該類的實例存儲在一個列表其他地方,這是我的日常節省:

Stream:=TFileStream.Create(FileName,fmCreate or fmOpenWrite); 
    for i := 0 to Macros.Count-1 do 
    begin 
    Macro:=TMacro(Macros[i]); 
    Size:=sizeof(Macro); 
    Stream.Write(size,SizeOf(integer)); 
    Stream.Write(Macro,sizeof(Macro)); 
    end; 

sizeof運算(微距)返回4字節,這將是指針,但我需要的實際空間的特定情況下發生。我首先想到的是得到Length(Command),因爲它是一個返回指針大小的動態結構。但是這意味着有類似SizeOf(Integer)+Length(Command)+SizeOf(boolean)+...的東西,但這對於進一步擴展TMacro結構是不利的。

那麼,有沒有辦法獲得包含動態類型的結構的大小?

謝謝你的答案

+0

您能否創建一個將實例保存在TMacro中的過程? – Ryan 2011-05-06 16:20:55

+0

你是什麼意思?如果你的意思是我創建了一個程序,它通過所有元素逐一去保存,然後是的,我可以(但我認爲有更好的方法)。但似乎我無法通過一次調用保存整個宏實例,因爲**字符串**類型。 – 2011-05-06 16:29:00

+0

我基本上是指梅森惠勒所說的。 – Ryan 2011-05-06 16:32:06

回答

4

如果要獲取TMacro的大小,請致電InstanceSize方法。但是,這不會幫助您將其封鎖到流中,並且它不會更改爲包含字符串的大小,因爲該字符串是引用類型。

你不能像這樣阻塞你的TMacro結構。首先,它是一個類,而不是一個記錄,這意味着它包含一個你不想保存的「魔術」字段(或者其中兩個,如果你使用的是Delphi 2009或更高版本)。其次,即使它是一條記錄,它仍然包含一個引用類型(字符串),所以數據不會內聯存儲在TMacro中;它存儲在堆中,必須單獨訪問。

如果你需要實現序列化,你可以用幾種不同的方法來完成。無論是打造一雙方法,像這樣:

procedure Load(savefile: TStream); //can also be implemented as a constructor 
procedure Save(savefile: TStream); 

,然後實現它們,讀/寫每場出一個接一個,或者使用某種具有RTTI的通用串行。這在Delphi 2010中編寫起來容易很多,因爲它具有更廣泛的可用RTTI功能。

2

由於一個Delphi對象是一個引用類型,SizeOf()返回一個參考,這是相同的指針的大小,在當前版本的Delphi 4個字節的尺寸。

如果您的記錄中的數據是值類型,則SizeOf()將返回內容的大小。

但是,由於您的結構包含受管理的類型,即字符串,因此不能簡單地將它保存在一個像這樣的大整數。您需要對字符串進行特殊處理。

如果我是你,我會保存信息項目。特別是,這使您可以控制諸如對齊之類的問題,並且可以支持版本控制。你可以很容易地編寫你自己的基本代碼來做到這一點。但是,如果出現以下情況,您可能需要考慮使用第三方框架:

  • 有很多字段需要堅持,並且單獨處理它們會導致非常費力的代碼。
  • 您想爲構建文件格式的版本提供一些靈活性。例如,當您添加新字段,更改現有字段的含義等時,您可能希望考慮未來版本的軟件會發生什麼情況。
+0

David:是否有框架使用RTTI來確定數據類型,然後正確處理磁盤到磁盤的流?或者這不可能? – RobertFrank 2011-05-07 00:36:43

+0

@robert我相信有很多,但我不知道他們。我一直寫自己的。 – 2011-05-07 06:33:29

0

如果你想SizeOf給你一個記錄的大小,然後你可以二進制持久化,你可以(雖然我個人不建議二進制記錄持久性)使用RECORD類型。

我相信,清晰度在這個問題上,不僅需要大衛的回答,石匠,也是corollarly原則:

如果中SizeOf(RECORDTYPE)是要figre什麼,首先使用記錄(未分類) ,第二次使用100種%的值類型,如字符數組(不是字符串)的結果是二進制持久化記錄:

type 
    TMyCharType = UnicodeChar; // or AnsiChar. Your choice. 
    PMacro = ^TMacro; 
    TMacro = record 
     Hotkey: Integer; 
     Command: Array [0..1000] of TMyCharType; 
     CTRLMode: Boolean; 
     RepeatInterval: integer; 
    end; 

作爲一個風格問題,我會更願意使用一些更高級的風格基於類的系統的持久性而不是基於記錄的二進制存儲。但是,如果這就是你想要做的,那麼就像我說的那樣使用RECORD而不是Class,也不要使用String。

此外,請注意,在您的代碼示例中,如果TMacro是一個類,則PMacro =^TMacro真的比差錯更糟。 (除非你真的想要做一些雙指針間接尋址。)

TMacro(引用類型)已經通過引用,所以不需要獲取它們的地址,因爲它們在內部被傳遞給變量鍵入TMacro(如果它是一個類)作爲指針。所以你真的需要在你的代碼中清晰地記錄Record類型和Value類型。

+0

謝謝。我宣佈PMacro只是因爲我陷入了一種方法(後來證明是錯誤的),所以它是多餘的,我忘了刪除它。無論如何,我嘗試過Char的Array [1..1000];但delphi沒有讓我把它作爲一個字符串(我相信String只是一個開放的字符數組?),並在我身上喊出「Incompatible types」。那麼是否可以基本上聲明一個> 256字符的固定字符串? (並像字符串一樣工作,即STR:='abcd') – 2011-05-08 08:00:39