struct msgA_
{
    int ix ;
    char msg[28] ;
    double dx ;
} ;
typedef struct msgA_ msgA ;

struct msgB_
{
    int iy ;
    char msg[28] ;
    char type[10] ;
} ;
typedef struct msgB_ msgB ;

struct msgC_
{
    int iz ;
    char msg[28] ;
    double x[6] ;
} ;
typedef struct msgC_ msgC ;


#define TYPEA 1
#define TYPEB 2
#define TYPEC 3


struct Packet_
{
    int PacketType ;
    union
    {
        msgA a ;
        msgB b ;
        msgC c ;
    }Pmsg ;
} ;
typedef struct Packet_ Packet  ;

void Test(char* ptr , unsigned int iLen )
{
    printf("(%d) for length\n",iLen) ;

    Packet* msgptr = (Packet*) ptr ;
    switch(msgptr->PacketType)
    {
    case TYPEA :
        printf("type A received \n") ;
        break ;
    case TYPEB :
        printf("type B received \n") ;
        printf("(%d)(%s)(%s)\n",msgptr->Pmsg.b.iy,
        msgptr->Pmsg.b.msg,msgptr->Pmsg.b.type) ;
        break ;
    case TYPEC :
        printf("type C received \n") ;
        printf("(%d)(%s)(%.1f)(%.1f)(%.1f)(%.1f)(%.1f)(%.1f)\n",
        msgptr->Pmsg.c.iz , msgptr->Pmsg.c.msg,
        msgptr->Pmsg.c.x[0],msgptr->Pmsg.c.x[1],
        msgptr->Pmsg.c.x[2],msgptr->Pmsg.c.x[3],
        msgptr->Pmsg.c.x[4],msgptr->Pmsg.c.x[5] ) ;
        break ;
    }
}


int main()
{

    Packet p1 ;
    p1.PacketType = 3 ;
    p1.Pmsg.c.iz = 10000 ;
    strcpy(p1.Pmsg.c.msg,"to be the one") ;
    p1.Pmsg.c.x[0] = 1.1 ;
    p1.Pmsg.c.x[1] = 2000.2 ;
    p1.Pmsg.c.x[2] = 3000.3 ;
    p1.Pmsg.c.x[3] = 4000.4 ;
    p1.Pmsg.c.x[4] = 5000.5 ;
    p1.Pmsg.c.x[5] = 6000.6 ;
    Test((char*) &p1,sizeof(p1)) ;

    printf("=========================\n") ;

    Packet p2 ;
    p2.PacketType = 2 ;
    p2.Pmsg.b.iy = 100 ;
    strcpy(p2.Pmsg.b.msg,"hello world") ;
    strcpy(p2.Pmsg.b.type,"type type") ;
    Test((char*) &p2,sizeof(p2)) ;
}

output :

(88) for length
type C received
(10000)(to be the one)(1.1)(2000.2)(3000.3)(4000.4)(5000.5)(6000.6)
=========================
(88) for length
type B received
(100)(hello world)(type type)

 

可以看到 , Packet 的變數 sizoeof 一率是 88 ,  這是因為 union 中去找到最大的 值 ,

然後不管你是使用 union那一種 structure ,  一率配給最高的那個 structure memory !!!!

struct Packet_
{
    int PacketType ;
    union
    {
        msgA a ;
        msgB b ;
        msgC c ;
    }Pmsg ;
} ;

這裡面 msgC 

struct msgC_
{
    int iz ;
    char msg[28] ;
    double x[6] ;
} ;

佔了 80 bytes 最高 ,  所以就是 80 bytes 加上此例中 int PacketType  8 bytes = 88 bytes !!!!!

首先 , msgC 為什麼是  80 bytes ?  4 + 28 + 6*8 = 80 bytes !!!!

那為甚麼 加上  PacketType  是 88 bytes 而不是 84 bytes ?  這是因為  natural alignment ,

double x 一定要配置在 memory alignment 是 8 的倍數的記憶體 ,  此例中唯有 PacketType 佔 8 bytes 才做的到 !!!!!

有無發現 msgC x[0] 剛好在  4 + 28 = 32 可以整除 8 , 所以此時的 iz 給 4 bytes 即可 !!!!!

 

Edit on 2014/01/01 :

struct s_
{
   char        c;
   double      d;
   int         s;
} structc_t;
 
這個 struct 的 size 應該是多少 ?  乍看 : 1(char) + 7(padding) + 8(double) + 4(int) = 20 bytes !!!!
很合理 , 所有的變數都在它長度的位子上 ,  但是 , 我們宣告  struct s_  xx[2] ;  那麼,  xx[1].d 位在 20 + 8 = 28 的記憶體上 ,
28 無法整除 8  , 所以答案不是 20 , 而是 24 !!!!  
 
簡單來說 , 每個變數都要在其 長度 的倍數上 ,  結構 array 也要合乎規則 !!!

 

Edit2 :

struct Mars_
{
    char a ;
    double d ;
    int  i ;
} ;

struct c_
{
    char a ;
    double d ;
    short s ;
    char arr[12] ;
};

在  32 bits OS Linux , Intel x86-64 cpu 是得到 :  16 , 28 , 64 bits OS Linux Intel x86-64 得到 24,32 ,

32 bits Linux 的值可以參考 :

http://en.wikipedia.org/wiki/Data_structure_alignment

其中一段話是重點 :

when compiling for 32-bit x86

A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux (8-byte with -malign-double compile time option).

 

 

#pragma pack(n)  就是限制對齊 n 而非 struct 最大的 member size

#pragma pack() 是 取消這個語法 !!!

此例中 , 你使用 pack(4) 你就會得到 84 , 如使用 pack(8) , pack(16) 沒有效果 ,  因為 大於 structure 最大 size 的 member

就沒有意義了 !!! 要注意的是 pack(4) 讓 double x 不是位在 memory 是 8 倍數上 , 最可能的危險是 :

這個變數可能 4 bytes 在 cache line 1 , 4 bytes 在 cache line 2 ,  此時就不能正常地 atomic 處理這樣的變數了 !!!!!

 

 

 

創作者介紹
創作者 hedgezzz 的頭像
hedgezzz

hedgezzz的部落格

hedgezzz 發表在 痞客邦 留言(0) 人氣()