2010年1月7日 星期四

Data structure alignment

前些時候將Structure內的資料以raw data的方式在處理時,才發現到原來Structure內的element並不是緊密相連在一起的。如以下例子:



typedef struct{

char str01[5];

long long01;

char str02[5];

char str03[5];

}TESTSTRUCT;

printf("Offset of long01:[%d]\n", ((char*)&tTest.long01)-((char*)&tTest));

printf("Offset of str02:[%d]\n", tTest.str02 - ((char*)&tTest));

printf("Offset of str03:[%d]\n", tTest.str03 - ((char*)&tTest));

printf("Sizeof TESTSTRUCT:[%d]\n", sizeof(tTest));

以VC在WinXP 32Bit的執行結果是:

Offset of long01:[8]

Offset of str02:[12]

Offset of str03:[17]

Sizeof TESTSTRUCT:[24]



可以看到long01在Structure內的Offset是8,而不是預期的5。這就是Data structure alignment的影響。可參考這裏的解釋。其主要就是為了程式Performance的關係。

同樣的,Structure的size變為24。也是Data structure alignment的影響。

在C/C++中要強迫Compiler使用多少padding數,可以用#pragma pack(n)這個語法來控制。

寫了十多年的C,最近才發現有這個問題。 XD

10 則留言:

  1. 介紹一下~Han是我跟大師(Nelson)大學/研究所的同窗兼室友。

    回覆刪除
  2. 沒錯~這個問題也是我在寫AVFarSight(一個號稱跨平台區網視訊串流的物件函式庫)才發現。當初是用structure在傳輸資料,才發現每個平台/compiler預設的padding設定不一樣,導致再比對長度時發生錯誤。解決方法也是用#pragma pack(n)明確指定。

    回覆刪除
  3. 作者已經移除這則留言。

    回覆刪除
  4. typedef struct{
    char str01[5];
    char str02[5];
    char str03[5];
    char str04[5];
    char str05[5];
    char str06[5];
    } test_struct2;

    為什麼跑出來是 30 ?


    ps. 我用< pre >他不給我用...

    回覆刪除
  5. 這是因為char的data padding值就是1,因為你的structure中的data type都是char,所以宣告多少就是多少。
    你可參考Wiki連結中的Typical alignment of C structs on x86章節的解釋。不同data type在不同os或Compiler裏,其padding值是不同的。

    回覆刪除
  6. #pragma pack(push) /* push current alignment to stack */
    #pragma pack(1) /* set alignment to 1 byte boundary */
    typedef struct _test
    {
    char ch0;
    char ch1;
    }test;
    #pragma pack(pop) /* restore original alignment from stack */

    請問為何 兩個 char 卻佔用 4 BYTES ?

    回覆刪除
  7. To 匿名
    請問在你的實驗中如果把ch1拿掉
    sizeof(test); 有變小嗎? 還是仍舊是4?

    回覆刪除
  8. TO Abow,
    我的環境是 arm linux 環境,
    發現結構內的成員都不變的話,用 typedef struct 跟 struct 宣告出來的結果是不一樣的...

    環境:arm LINUX C++

    struct REGS_A
    {
    char lo ;
    char hi ;
    char hi2 ;
    }__attribute__ ((packed ));



    typedef struct
    {
    char lo ;
    char hi ;
    char hi2 ;
    }REGS_B __attribute__ ((packed ));


    計算結構的大小
    printf("REGS_A size : %d\n" , sizeof( struct REGS_A ) ); ---> 3
    printf("REGS_B size : %d\n" , sizeof( REGS_B ) ); ---> 4

    typedef struct 宣告的結構大小都會是回傳 4 的倍數


    PS: 其實不知道 typedef struct 是否可以搭配 __attribute__ ((packed )); ,但是編譯過程沒有出現任何訊息。 但是 packed 卻沒有發揮效果...

    回覆刪除
  9. 我在Mac OS X (gcc)實驗的結果都是 3

    回覆刪除