2015年3月2日 星期一

union的使用時機&struct的對齊(natural alignment)

繼前篇所討論的struct與union的差異, 這邊有個使用union的範例可以參考~

假設現在有三個種類的封包要被傳送, 而同一時間只會送出這三類的其中一類封包, 同時我們用struct與union兩種方式宣告, 在執行結果進行比較所需佔用的記憶體空間。

因此程式可以這樣寫:



//*****************example_union_usage.c****************//

#include <stdio.h>

struct structA
{
   int a;
   char b;
};

struct structB
{
   char a;
   short b;
};

struct structC
{
   int a;
   char b;
   float c;
};

struct CommuPacket       //使用union的
{
   int iPacketType;
   union
   {
        struct structA packetA;
        struct structB packetB;
        struct structC packetC;
   };
};

struct CommuPacket_2
{
   int iPacketType;
   struct
   {
        struct structA packetA;
        struct structB packetB;
        struct structC packetC;
   };
};

int main()
{
   struct CommuPacket struct_CommuPacket;
   struct CommuPacket_2 struct_CommuPacket_2;

   int struct_size, struct_size_2;
   struct_size = sizeof(struct_CommuPacket);
   struct_size_2 = sizeof(struct_CommuPacket_2);

   printf("struct_CommuPacket size=%d\n", struct_size);
   printf("struct_CommuPacket_2 size=%d\n\n", struct_size_2);

   int m_size_packetA, m_size_packetB, m_size_packetC;

   m_size_packetA = sizeof(struct_CommuPacket.packetA);
   printf("packetA size is %d\n", m_size_packetA);

   m_size_packetB = sizeof(struct_CommuPacket.packetB);
   printf("packetB size is %d\n", m_size_packetB);

   m_size_packetC = sizeof(struct_CommuPacket.packetC);
   printf("packetC size is %d\n", m_size_packetC);
}

//***************************************************//

輸出結果:



可以看到使用union的,佔了16byte,與struct的28byte比較,小了許多。

========================================================================






另外你可能會有疑問,為什麼packetA,packetB,packetC的size分別是8byte,4byte,12byte?

照理說不是應該是5byte,3byte,9byte嗎?

這就要講到struct的"自然對齊"(natural alignment)特性與"指定對齊":


一. natural alignment,是指按結構體的成員中size最大的成員對齊。

舉個例子:

struct natural_alignment
{
char a;
short b;
char c;
};

在上述struct中,size最大的是short,其長度為2byte,因而結構中的char成員a、c都以2為單位對齊,sizeof(natural_alignment)的結果等於6;



如果改為:

struct natural_alignment
{
char a;
int b;
char c;
};

其結果顯然為12。



二. 還有另外一種用法名為"指定對齊"

通常可以通過下面的方法來改變指定對齊的條件:

  • 使用虛擬指令#pragma pack (n),編譯器將按照n個位元組對齊;
  • 使用虛擬指令#pragma pack (),取消自定義位元組對齊方式

*如果#pragma pack (n)中指定的n大於結構體中最大成員的size,則沒有作用,結構體仍然按照size最大的成員進行對齊。


例如:

#pragma pack (n)
struct natural_alignment
{
char a;
int b;
char c;
};
#pragma pack ()
  當n為4、8、16時,其對齊方式都一樣,sizeof(naturalalign)的結果都等於12。而當n為2時,sizeof(naturalalign)的結果為8。

在VC++ 6.0編譯器中,我們可以指定其對齊條件,其操作方式為依次選擇projetct > setting > C/C++功能表,在struct member alignment中指定你要的對齊條件。

另外,通過__attribute((aligned (n)))也可以讓所作用的結構體成員對齊在n位元組邊界上,但是它較少被使用。







沒有留言:

張貼留言