天天看點

位元組對齊不同造成結構體成員指派失敗

我們知道,C編譯器在編譯32位機目标代碼時,預設将變量存儲的位址按照4位元組進行對齊。

在使用結構體時,由于位元組對齊的原因可能會造成存儲空間的浪費

例如:

struct AA{

    char a;

    int b;

    char c; 

}aa

結果,sizeof(aa)=12。成員a與b之間空出了3個空位元組,成員c也後也空出了3個位元組。

這個時候雖然記憶體空間有些浪費,但是并不會誤導程式員進行編碼。如果和聯合體一起使用,就可能會造成一定的誤解。

例如:

struct AA{

    union{

    struct{

  char Byte0;

     char Byte1;

     char Byte2;

     char Byte3;

  };

    int data;

 }

}aa

此處本來想将 Byte0 -Byte3作為 data的4個位元組的重名以便對data的其中任意8bit進行操作。但是由于四位元組對齊的原因隻有Byte0是data的第0位元組,Byte1-Byte3每一個成員都向後偏移了四個位元組。

為了達到預期的效果,可以使用#pragma pack(n) 對編譯器進行位元組對齊設定。

#pragma pack(1)//按照1位元組進行對齊

struct AA{

    union{

    struct{

  char Byte0;

     char Byte1;

     char Byte2;

     char Byte3;

  };

    int data;

 }

}aa #pragma pack()//取消對齊設定 這樣就可以達到預想的效果,使用Byte0-Byte3對data的每個位元組進行單獨的操作。

但是今天,由于我在使用#pragma pack() 指令犯了錯誤,産生了結構體成員指派失敗的情況。 情況如下: 檔案a

struct AA{

    char a;

    char b;

    char c; 

}aa

檔案b #pragma pack(1)//按照1位元組進行對齊

struct _cc{

    union{

    struct{

  char Byte0;

     char Byte1;

     char Byte2;

     char Byte3;

  };

    int data;

 }

}cc

 aa.b = 0x02;//此處給成員b指派失敗

#pragma pack()//取消對齊設定

我在檔案a中使用預設的對齊設定(4位元組對齊),建立了結構體aa。然後aa作為全局變量在檔案b中進行指派。 但檔案b由于cc結構體的需要設定了1位元組對齊 對結構體aa成員的指派語句放在了取消對齊設定之前,編譯器在編譯檔案b時對變量aa.b按照1位元組對齊進行了操作,是以成員b的偏移位址為1。而實際上在定義aa時,成員b的偏移位址為4(a與b之間插入了3個空位元組) 是以指派并沒有成功,而是将0x02寫入了aa.a 與aa.b中間的填充位元組。 在仿真這段程式時,就出現了指派不成功的奇怪現象。

那麼應該如何解決這個問題呢? 那就是謹慎的使用#pragma pack(n)指令

将需要對齊的結構體聲明放在#pragma pack(n) 與 #pragma pack()之間,其他的代碼不要放在這裡面,特别是對對齊設定不同的結構體進行通路的代碼段。 檔案b改為 #pragma pack(1)//按照1位元組進行對齊

struct _cc{

    union{

    struct{

  char Byte0;

     char Byte1;

     char Byte2;

     char Byte3;

  };

    int data;

 }

}cc #pragma pack()//取消對齊設定  aa.b = 0x02;//此處給成員b指派成功

繼續閱讀