最近碰到一道题,顺带复习一下union的数据分布,题目如下:

union packet
{
struct packet_bit
{
unsigned char a:2;
unsigned char b:3;
unsigned char c:4;
} bit;
int i;
} data;
int main()
{
data.i = 0;
data.bit.a = 1;
data.bit.b = 2;
data.bit.c = 15;
printf("0x%04x\n",data.i);
return 0;
}

先来看一下struct packet_bit是如何分布的

成员a、b、c都是char型,所占的位数为2,3,4。由于union类型不能跨字节(本题为unsigned char,为单字节),所以a、b在同一个字节内,后面补3个位,c在第二个字节内。而struct packet的size为4个字节,所以其分布图如下:


(第一字节)                    (第二字节)

—— —— —— —— —— —— —— ——|—— —— —— —— —— —— —— ——|后16位为0(两个字节)

          (     b    )(  a   )            (     c       )

因为字节填充是从低位填起,所以a、b、c的分布情况如上图,由不同的颜色标出。


所以,当执行赋值语句后,a=1,b=2,c=15,对应上图的情况是:


(第一字节)                    (第二字节)

—— —— —— 0 1 0 0 1|—— —— —— —— 1 1 1 1|后16位为0(两个字节)

           (  b  ) ( a )             (    c    )


所以data.i在大端的情况下的值为:0x090f0000

小端的情况下,值为:0x00000f09。

所以上面的答案为 0x0f09。(intel cpu)


关于union不能跨类型字节的理解,可以看下面这个例子:

#include <stdio.h>
#include <stdlib.h>
typedef struct _strBitData_
{
unsigned int  ulData1:2;
unsigned int  ulData2:12;
unsigned int  :2;
}strBitData;
typedef struct _chBitData_
{
unsigned char  ulData1:2;
unsigned char  ulData2:7;
unsigned char  :2;
}chBitData;
int main()
{
strBitData stData;
chBitData chData;
unsigned int *pOuputData;
unsigned char *pchOuputData;
memset((void*)&stData, 0, sizeof(strBitData));
memset((void*)&chData, 0, sizeof(chBitData));
stData.ulData1 = 0x7;
stData.ulData2 = 0x010;
chData.ulData1 = 0x7;
chData.ulData2 = 0x010;
pOuputData = (unsigned int *)&stData;
pchOuputData = (unsigned char *)&chData;
printf("0x%x\n", *pOuputData);
printf("0x%x\n", *pchOuputData);
return 0;
}
结果为:0x43

       0x3

如果位域在类型的范围内,则拼接,否则,不可以跨类型拼接。

还需要注意的是,0x7被截断成为两个位,故为0x3