2021年1月10日 星期日

結構體位元組對齊 pragma pack,__attribute__(packed)

程式編譯器對結構的儲存的特殊處理確實提高CPU儲存變數的速度,但是有時候也帶來了一些麻煩,我們也屏蔽掉變數預設的對齊方式,自己可以設定變數的對齊方式。


例如我們設定結構體的對齊方式:

struct student

{

    int age;

    char c;

};


對於以上結構體,預設用sizeof輸出大小為8位元組,預設的位元組對齊方式是4,當然我們也可以設定他的對齊   方式,如下:


#pragma pack(2) //(或 pragma(push,4))

struct student

{

    int age,

    char c;

};


#pragma pack(pop) //注意這個和push是成對用的


此時用sizeof輸出大小是為6,因為對齊方式為2.如果設定對齊方式為1的話,sizeof輸出大小則為5;


當然有時我們不希望編譯器對結構體做對齊處理,而希望按照他原有的大小分配空間,這裡就要用到  __attribute__((packed)) ,這個意思是告訴編譯器不要做對齊處理。


struct Student

{

    int age;

    char c;

}__attribute__((packed));


int main()

{

    struct Student S;

    printf("%d\n",sizeof(S));

}


輸出大小為 5,其實和一位元組對齊方式一樣。


到這裡可能許多人和我剛開始一樣不理解這個__attribute__((packed)) 是個什麼東東,這個其實是GUN C   的一大特色,是一種機制,他可以設定函式屬性,變數屬性,型別屬性,packed就是個型別屬性。


   當然__attribute__還可以用來設定位元組對齊屬性。


   __attribute__((aligned(4)));設定4位元組對齊方式,和#pragma pack(4) 效果一樣,我的總結大概就是這   些,希望對大家有用,麼麼噠。


#include <stdio.h>


typedef struct Student_t

{

int age;

char c;

}__attribute__((packed)) Student;


typedef struct Node_t

{

int a;

char c;

}__attribute__((aligned(4))) Node;


#pragma pack(push,1)

typedef struct List_t

{

int a;

char c;

}List;

#pragma pack(pop)


int main()

{

Node A;

List B;

Student C;

printf("%d,%d,%d\n",sizeof(A),sizeof(B),sizeof(C));

return 0;

}



輸出大小依次為:8,5,5


寫到這裡順便再補充一下,通常在跨平臺的基於資料結構的網路通訊的時候特別要注意位元組的對齊方式,以為在不同的系統中,某些型別的大小不一樣。


                  short       int    long       long long          ptr     time_t

     32位           2         4       4             8                    4        4

     64位           2         4       8             8                    8        8


在定義通訊用的結構體時,應該考慮使用定常的資料型別,如uint32_t,4位元組的固定長度,並且這屬於標準C庫(C99),在各系統中都可使用。

沒有留言:

張貼留言