2011-09-12 185 views
1

語言是C,gcc編譯sizeof操作符返回奇怪結果

如果我像這樣

struct test { 

    char item_1[2]; 
    char item_3[4]; 
    char item_4[2]; 
    char item_5[2]; 
    char item_6[4]; 

}; 

一個結構,我做的sizeof(結構測試)返回14(字節)。這是預期的結果。

,但如果我這樣做

struct test { 

    int16_t item_1; 
    int32_t item_3; 
    int16_t item_4; 
    int16_t item_5; 
    int32_t item_6; 

}; 

的sizeof(結構測試)當我調試使用GNU DDD將返回喜歡44一些奇怪的事情,我可以在結構內部看,看到這一切看起來正常,所有項目都預期的字節數。

那麼爲什麼sizeof運算符返回一個意外的值?

+2

int16_t [2] = 4字節* 3 = 12個字節; int32_t [4] = 16字節* 2 = 32字節; 12 + 32 = 44. – Jon

回答

1

編譯器可以在結構成員之間或最後一個成員之後插入填充。這通常是爲了滿足對齊要求。例如,一個int32_t對象可能需要4字節對齊,所以編譯器會在第一個和第二個成員之間插入2個字節的填充。細節會根據平臺而有所不同。

+0

感謝Keith Thompson和sqykly我現在明白了 – maxim

3

您混合了32/16位整數。

int16_t item_1[2]; // 2 * 2 = 4 
int32_t item_3[4]; // 4 * 4 = 16 
int16_t item_4[2]; // 2 * 2 = 4 
int16_t item_5[2]; // 2 * 2 = 4 
int32_t item_6[4]; // 4 * 4 = 16 
        // sum = 44 
+0

我的錯誤,我不能編輯我的文章。我需要編寫結構測試{ int16_t item_1; int32_t item_3; int16_t item_4; int16_t item_5; int32_t item_6; }; – maxim

+0

點擊您的代碼下方的修改鏈接。 –

+1

@maxim:註釋中被修改結構的大小爲16字節,因爲編譯器正在添加填充字節以確保對齊的內存訪問。 –

0
struct test { 
    int16_t item_1[2]; // 2 * 16 + 
    int32_t item_3[4]; // 4 * 32 + 
    int16_t item_4[2]; // 2 * 16 + 
    int16_t item_5[2]; // 2 * 16 + 
    int32_t item_6[4]; // 4 * 32 
         // total = 352 
}; 

352位除以8(8位進入一個字節)是44個字節。

+0

我實際上沒有數組寫入sencond結構。只是單一的價值觀。它回調16而不是14 – maxim

1

編譯器需要在結構成員之間插入填充以將其類型邊界上的每個成員對齊,並按照書面順序排列結構的成員。如果您重新排列它們以使最大的成員位於結構定義的開始位置,則它們將具有相同的大小。但是,既然你用char數組來嘗試它,我猜你沒有結構的原始定義,並且你試圖訪問一些外部定義和創建的對象的字段。在這種情況下,我建議你要麼獲得正確的頭文件,要麼使用char []版本,並將char *轉換爲真正的類型。

1

對齊問題是因爲現代32位CPU在32位地址邊界上以32位字大小工作。如果32位邊界上的32位字包含2個16位值,則會導致需要額外的指令來獲得正確的16位(即掩碼和移位,以便保留正確的16位) 。如果一個32位字跨越32位邊界分裂,那麼檢索它還有更多工作要做。

默認情況下,權衡是讓程序更快,並且儘可能不使用內存。如果在使用結構構件的任何地方都需要額外的幾條指令,那麼這可能會比使用更緊密的包裝結構節省更多的內存,所以雖然不明顯,但首先它是正確的選擇。

如果您需要有效地存儲結構(以性能爲代價),那麼「#pragma pack」允許您更緊縮包成員,但會導致更慢的程序。

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

http://www.cplusplus.com/forum/general/14659/