2013-10-20 24 views
1

我在Ada類型記錄中遇到了一些麻煩。 我正在使用Sequential_IO讀取二進制文件。要做到這一點,我必須使用大小爲文件大小倍數的類型。在我的情況下,我需要的50個字節的結構,所以我創建的類型是這樣的(「Vecteur」爲3浮法的陣列):Ada:記錄類型的變體大小

type Double_Byte is mod 2 ** 16; for Double_Byte'Size use 16; 

type Triangle is 
    record 
     Normal : Vecteur(1..3); 
     P1 : Vecteur(1..3); 
     P2 : Vecteur(1..3); 
     P3 : Vecteur(1..3); 
     Byte_count1 : Double_Byte; 
    end record; 

當我使用類型三角形的尺寸是52個字節,但是,當我把它中的每一個的大小分開,我發現50個字節。因爲52不是我文件大小的倍數,所以我有執行錯誤。但我不知道如何解決這個問題,我運行了一些測試,我認爲它來自Double_Byte,因爲當我從記錄中刪除它時,我發現它的大小爲48個字節,而當我將它放回時,它又是52個字節。

謝謝你的幫助。

回答

1

除非您指定它,否則編譯器沒有義務爲Triangle使用特定的大小。如果您不這樣做,它會選擇適合快速訪問數據的任何大小。即使您爲記錄的每種組件類型指定了表示詳細信息,編譯器仍可能會選擇爲記錄本身使用更多空間。

考慮到您提供的尺寸,似乎很明顯,Vecteur的一個組件有4個字節,因此Triangle的總有效負載爲50個字節。編譯器現在選擇添加2個字節的填充,以便記錄大小是4-byte word大小的倍數。您可以用下列方法覆蓋此行爲:

for Triangle'Size use 50 * 8; 

這將強制編譯器僅使用50個字節的記錄。由於這是一個緊密的配合,只有一種方法來表示記錄,不需要進一步的說明。如果您確實需要指定記錄的表示方式,則可以使用record representation clause

編輯:

的表示子句爲類型的大小。然而,這種類型的每個對象仍可能佔用更多的空間,除非你另外指定

pragma Pack (Triangle); 

編輯2:

西蒙的評論後,我曾在這個定睛一看,意識到有一個更好更清潔的解決方案。而不是設置'Size和使用pragma Pack的,這樣做:

for Triangle use record at mod 2; 
    Normal  at 0 range 0 .. 95; 
    P1   at 12 range 0 .. 95; 
    P2   at 24 range 0 .. 95; 
    P3   at 36 range 0 .. 95; 
    Byte_count1 at 48 range 0 .. 15; 
end record; 

初始mod 2限定該記錄是在2個字節的倍數對齊。這消除了末尾的填充,而不需要pragma Pack(這不能保證在每個編譯器上都以相同的方式工作)。

+0

謝謝你的回答。我只是試圖把你說的大小,但我仍然有同樣的問題,最後的大小是52字節... –

+0

啊,是的,我忘了一些東西,看我的編輯。 – flyx

+0

現在感謝您的支持。 –

2

鑑於Simon的最新評論,使用Sequential_IO可能無法做到這一點便攜式;即在某些機器上讀取文件(不支持未對齊的訪問)可能會使其內容的一半保持不對齊,因此在訪問它們時可能會失敗。

我不禁覺得更好的解決辦法是將數據格式(通過與其他系統的兼容性來解決)與數據格式(不是)分開。因此,如果需要(例如,將奇數大小的Double_Byte組件打包爲2個字節,無論它在內存中的表示如何),都將轉移到Stream_IO並編寫您自己的基本代碼ReadWrite,這將是一個更強大的解決方案。

然後你可以保證文件格式與其他系統兼容,並保證內存格式的工作。