給定一個有33個專案的列舉TEnum(Ceil (33 / 8) = 5位元組),以及一個TEnumSet = Set of TEnum,當在32位和64位Windows中運行時,SizeOf (TEnumSet)給出不同的結果:
- 32位。根據上面的計算,5個位元組
- 64位:5個位元組
- 64位。8個位元組
當增加列舉中的元素數量時,其大小將變化為,例如,在32位中為6位元組,而在64位中,仍為8位元組。仿佛64位的記憶體對齊方式是將大小四舍五入到最接近的XX的倍數?(不是8,較小的列舉確實產生了2,或4的集合大小)。) 而2的冪也很可能不是這種情況。
在任何情況下:當從32位程式中讀取一個檔案到一個寫成緩沖區的打包記錄時,這就造成了一個問題。試圖將同一個檔案讀回一個 64 位程式,由于打包的記錄大小不匹配(記錄中包含這個不匹配的集合,以及其他一些東西),讀取失敗。
我試著在編譯器選項中尋找一些與記憶體對齊有關的選項:有一個關于記錄記憶體對齊的選項,但它并不影響集,而且在兩種配置中已經是一樣的。
請解釋一下為什么在 64 位中集合會占用更多的記憶體,以及任何可能的解決方案,以便能夠在 64 位平臺上將檔案讀入我的打包記錄中?
請注意,我無法控制檔案的寫入:它是用一個我無法訪問的32位程式寫入的(所以改變寫入方式是不可能的)。
uj5u.com熱心網友回復:
這里是我的測驗程式:
{$APPTYPE CONSOLE}
型別
TEnumSet16 = set of 0.16-1。
TEnumSet17 = set of 0.17-1;
TEnumSet24 = set of 0.24-1。
TEnumSet25 = set of 0.25-1。
TEnumSet32 = set of 0.32-1。
TEnumSet33 = set of 0.33-1。
TEnumSet64 = set of 0.64-1。
TEnumSet65 = set of 0.65-1。
begin.
Writeeln(16, ':', SizeOf(TEnumSet16))。
Writeln(17, ' :', SizeOf(TEnumSet17))。
Writeln(24, ' :', SizeOf(TEnumSet24))。
Writeln(25, ' :', SizeOf(TEnumSet25))。
Writeln(32, ' :', SizeOf(TEnumSet32))。
Writeln(33, ' :', SizeOf(TEnumSet33))。
Writeln(64, ' :', SizeOf(TEnumSet64))。
Writeeln(65, ' :', SizeOf(TEnumSet65))。
end。
還有輸出(我使用的是XE7,但我希望它在所有版本中都是一樣的):
拋開 32 與 64 的差異不談,請注意 17 和 24 位的情況理論上可以放在 3 位元組型別中,它們被存盤在 4 位元組型別中。
為什么編譯器選擇使用 4 位元組型別而不是 3 位元組型別?這只能是為了讓代碼更加高效。對可直接映射到 CPU 暫存器上的資料進行操作比逐個位元組地挑選資料更有效率,或者在這種情況下,在一次操作中訪問兩個位元組,然后在另一次操作中訪問第三個位元組。
這就說明了為什么33和64位之間的任何東西在64位編譯器下都被映射為8位元組的型別。64 位編譯器有 64 位暫存器,而 32 位編譯器則沒有。
至于如何解決你的問題,那么我可以看到兩個主要的方法:
。
- 在你的64位程式中,逐欄位讀寫記錄。對于那些受到32位與64位問題困擾的欄位,你將不得不引入特殊的代碼來讀寫該欄位的前5位元組。
- 改變你的記錄定義,用
array [0...4] of Byte取代set,然后引入一個屬性,將set型別映射到5位元組的陣列上。
uj5u.com熱心網友回復:
處理一個集合的記憶體大小,遲早會導致處理錯誤。這一點在處理子型別時變得尤為明顯。
program Project1。
us
System.SysUtils;
type
TBoolSet=set of boolean;
TByteSet=set of byte;
TSubEnum1=5.10。
TSubSet1=set of TSubEnum1。
TSubEnum2=205.210。
TSubSet2=set of TSubEnum2;
var
i, j: 整數。
a, a1: TByteSet。
b, b1: TSubSet1。
begin
try try
writeln('SizeOf(TBoolSet): ', SizeOf(TBoolSet)); /1
writeln('SizeOf(TByteSet): ', SizeOf(TByteSet)); /32
writeln('SizeOf(TSubSet1): ', SizeOf(TSubSet1)); /2
writeln('SizeOf(TSubSet2): ', SizeOf(TSubSet2)); /2
//Assignments are allowed.
a := [6, 9] 。
b := [6, 9] 。
writeln('a = b ? : ', BoolToStr(a = b, true)); /true
a1 := a b; //OK
b1 := a b; //ol
a := [7, 200] 。
b1 := a b; //? ?? 沒有例外,值200被丟失。!
i := 0;
for j in b1do
i := succ(i);
writeln('b1 Count: ', i);
readln(i);
except[/span
on E: 例外 do
Writeln(E.ClassName, ': '/span>, E.Message)。
end。
end。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/316493.html
標籤:
