簡體   English   中英

C / C ++獲得結構大小

[英]C/C++ getting struct size

今天,我驚訝地發現了這一點

當sizeof運算符應用於類,結構或聯合類型時,結果是該類型的對象中的字節數,以及為在單詞邊界上對齊成員而添加的任何填充。 結果不一定與通過添加各個成員的存儲要求而計算的大小相對應。

我不知道它,我很確定這個東西打破了我的一些舊代碼:讀取二進制文件,我曾經有這樣的結構:

struct Header
{
    union {
        char identc[4];
        uint32 ident;
    };
    uint16 version;
};

並使用sizeof驅動的fread直接讀取這6個字節:

fread( &header, sizeof(header), 1, f );

但是現在sizeof(header)返回8


是否有可能使用較舊的GCC版本sizeof(header)返回6 ,或者我的想法完全消失了?

無論如何是否有任何其他運算符(或預處理器指令或其他)讓編譯器知道結構有多大 - 不包括填充?

否則,從一個不需要編寫太多代碼的文件中讀取原始數據結構的干凈方法是什么?


編輯 :我知道這不是讀取/寫入二進制數據的正確方法:根據機器的字節順序和內容,我會得到不同的結果。 無論如何,這種方法是最快的方法,我是juist試圖讀取一些二進制數據以快速獲取其內容,而不是編寫一個我將在未來使用或發布的好應用程序。

你想要的是#pragma pack命令。 這允許您將包裝設置為您想要的任何數量。 通常,您會在結構定義之前將打包值設置為1(或者是0?),然后在定義之后將其返回到默認值。

請注意,這並不能保證系統之間的可移植性。

另請參閱: 使用-pragma-in-c以及關於SO的各種其他問題

是的,您提供的代碼不可移植。 不僅結構大小而且字節順序可能不同。

這不是處理二進制文件的正確方法。 除了對齊問題外,它還存在字節序問題。 讀取二進制文件的正確方法是使用uint8_t (或unsigned char ,它確實無關緊要)和您自己的函數來構建數據中的內存表示。

大多數編譯提供了一個特定的擴展,允許您控制結構的打包。 這應該允許你控制它。 但是,當您以二進制形式編寫結構時,您應該能夠只編寫並讀取它而不管打包,就像編寫結構時一樣,它也應該寫sizeof(struct)字節。 如果您想要讀取使用以前版本創建的文件,那么這將是一個麻煩的唯一情況。 此外,您需要考慮字節順序問題等。

您的問題是特定於編譯器的,但通常如果您構建結構使得每個成員位於與其自身相同大小的邊界上(可被4整除的邊界上的四個字節元素等),您將獲得所需的行為。 還要注意像你所呈現的那樣的情況,其中填充位於結構的末端,以對齊下一個結構的第一個元素的開始 - 如果它們是以數組布局的。

看來你有問題,所以我不確定為什么我甚至都想回答! 但是,包裝很重要,並且會根據編譯器版本,標志,目標架構編譯指示,風向,月球相位以及可能的許多其他內容而發生變化。 將二進制文件轉儲到文件(或套接字)並不是一種很好的序列化方法。

當您創建這些結構的數組時,這個額外的填充是使成員正確對齊所必需的。 沒有它,數組的第二個元素將使ident成員在一個不是4的倍數的地址上對齊。

對它做任何事情都可能為時已晚,你可能以前用這種結構編寫了文件。 更改打包將使這些文件不可讀。 但是,是的,擁有依賴於編譯器設置的文件數據並不是最好的主意。 如今,將數據以人類可讀的格式存儲是很常見的。 磁盤字節和CPU周期都不值得。

是的,對齊問題。 這就是互聯網協議消息具有對齊結構的原因,以便在通過網絡發送數據時可以避免此問題。

您可以做的是修復結構以使它們正確對齊,或者具有在保存和檢索數據時使用的編組功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM