C中結構體和字節流的互換及內存對齊

 

mystruct p;
char buff[50];
memcpy(buff,&p,sizeof(p)); //把p的內容以字節形式拷貝到buff中
mystruct* q;
q = (mystruct*)buff; //把buff的內容轉換爲結構體mystruct網絡

 

或者spa

(將字節流轉化成結構體)指針

msg_header_t msgRecved;內存

num = data_recv(fd,(void *)buf,sizeof(msg_header_t));編譯器

memcpy(&msgRecved,buf,sizeof(msg_header_t));編譯

 

常常須要在程序中將遠程傳來的字節流進行結構化,或者將結構化的數據變成字節流傳給遠程主機。變量

在C/C++程序中,結構化數據一般用結構體來組織,結構體也可以方便的轉換爲字節流,所以結構化的數據傳輸本不應成爲問題,序列化

但在VC或GCC的默認設置下編譯出的程序,卻有一個值得注意的問題——結構體的對齊。    二進制

結構體的對齊是編譯器爲加快程序運行,在結構體中填入一些空白字節,是的結構體成員按必定規則對齊。

例如結構: 
struct MyStruct 
{     
char a;     
int  b; 
};
   
     按通常計算其類洗過那大小應爲5個字節,但在上述編譯器默認設置下,使用sizeof計算出的結構體類型大小爲8個字節,由於編譯器在該結構的第一個成員後填入了3個字節來保持成員的對齊。這樣,在序列化字節流的時候就產生了問題,該結構類型的變量指針直接轉化成char *或者使用memcpy得出的字節流即爲8個字節而非5個字節。通常狀況下,傳輸規約只定義有效字節,於是上述方式產生的字節流中3個字節將不在規約中定義,所以遠程主機在解析的時候會產生誤解,固然除非遠程解析程序採用一樣的序列化方式和一樣的結構對齊設置,而這在某些狀況下難以保證。因此,在結構的序列化過程當中,必須僅處理有效字節,使得字節流符合規約定義。
    多餘字節的產生緣由在於編譯器對結構體成員對齊字節數的設置的不一樣,VC和GCC(MinGW)的默認設置爲8字節對齊,因此須要改變其默認的對齊字節數爲按單字節對齊,便可以解決上述問題。具體方法是在代碼頭中加入: 
   #pragma pack(1)便可。
   此後使用sizeof計算出的結構體大小即爲各成員大小的總和。這在按既定規約編寫網絡二進制數據傳輸程序時須要注意;程序

 

 

內存對齊的問題:
重要的是,數據是否有拿對。
天然對齊,是變量的內存地址,正好是它類型長度的整數倍;
 
對於結構體,
若採用
 
struct std{
        char data[9];
        int person;
        } __attribute__((aligned (1)));
 
        struct std my_std;
 
        printf("size of my student = %d\n",sizeof(my_std));    ===> 結果是16
 
struct std1{
        char data[9];
        int person;
        } __attribute__((packed));
 
        struct std1 my_std1;
 
        printf("size of my student1 = %d\n",sizeof(my_std1));===> 結果是13
 
若沒有 __attribute__((packed)),則按照四字節對齊,
 
舉例
std結構體中data 爲4字節對齊的字節流數據;
 
int len;
len = *(int *)&data[7];
7非4的整數倍,就會出現拿不到想要的數據問題;
 
data[4] data[5] data[6] data[7] 用上述方法拿到的數據同樣。
前面的*(int*) 至關與一個「耦煤器「 ,它不會從地址對齊的當前塊跨越到下一塊。
 
 
修改爲:
char len[4];
memset(len,0,sizeof(len));
memcpy(len,&data[7],sizeof(len));
則能拿到想要的數據;
 
 
 
相關文章
相關標籤/搜索