联合体(union)以及数据的存储
当多个数据需要共享内存或多个数据每次只取其一时,可以利用联合体(union),有关联合体的描述如下:
1.联合体是一个结构;
2.它的所有成员相对于基地址的偏移量都为0;
3.此结构空间要大到足够容纳最"宽"的成员;
4.其对齐方式要适合其中所有的成员。
对上面四句话的理解:
由于联合体的所有成员是共享一段内存的,因此每个成员的存放首地址相对于联合体变量的基地址额偏移量为0,即所有成员的首地址都是一样的。为了使得所有成员能够共享一段内存,因此该空间必须足够容纳这些成员中最宽的成员。再来着重介绍一下什么叫"对其方式要适合其中所有的成员"?
例如:
#include<stdio.h>
typedef struct u
{
char a;
int b;
}U1;
int main()
{
printf("%d\n",sizeof(U1));
return 0;
}
假设U1按如下方式内存方式布局(内存地址从左至右递增):
因为U1中有最强对齐要求的是b字段(int),所以U1对象的首地址一定是4的倍数,那么上述内存的布局中的b字段能满足int类型的对齐要求吗?显然是不能的,于是有了如下的地址分配方案:
这个方案在a与b之间多分配了3个填充(padding)字节,这样当整个struct对象首地址满足4字节的对齐要求时,b字段也一定能满足int型的4字节对齐规定。那么sizeof(U1)显然就应该是8,而b字段相对于结构体首地址的便宜就是4。我们看一下程序给的结果吧:
那么下面这个呢?
typedef struct u2
{
int a;
char b;
}U2;
其实和上例子是一样的,sizeof(U2)也是8。
好的,现在你已经掌握了结构体内存布局的基本准则,尝试分析一个稍微复杂点的类型吧。
例如:
typedef struct u
{
char a[9];
int b;
double d;
}U1;
先来分析一下,a占9字节,b占4字节,d占8字节,这里最"宽"的变量是a,因此内存大小至少是9。像上面的例子一样,U1的地址最前面是9个字节,然后在a和b之间多分配了3个填充(padding)字节,在然后是b的4个字节,最后是d的8个字节。sizeof(U1)=24。看看程序运行的结果吧:
#include<stdio.h>
typedef struct u
{
char a[9];
int b;
double d;
}U1;
int main()
{
printf("%d\n",sizeof(U1));
return 0;
}
下面来个有关union使用的测试程序加深理解:
#include<stdio.h>
union un
{
int i;
short int si[2];
char c[4];
}u;
int main()
{
u.c[0]='A';
u.c[1]='B';
u.c[2]='C';
u.c[3]='D';
printf("u.c[0]=%d,u.c[1]=%d,u.c[2]=%d,u.c[3]=%d\n",u.c[0],u.c[1],u.c[2],u.c[3]);
printf("u.si[0]=%d,u.si[1]=%d\n",u.si[0],u.si[1]);
printf("u.i=%d\n",u.i);
return 0;
}
在程序中,由于联合体的特点,变量x占4个字节。我们可以从3个角度观察这4个字节:
(1)整体看,是一个int型数据;
(
2)分成2部分看,是两个短整型数据;
(3)分成4部分看,是4个单字节的数据。
但无论怎么看,就是这4个字节。无论用哪种形式操作数据,使用的也就是这4个字节。联合体为我们提供了从不同的角度使用这4个字节的方式。
x.c[0]到x.c[3]的值分别为65\66\67\68,这好理解。
x,si[0]占2字节,与x.c[0]和x.c[1]相同。验证一下:16961=66*256+65(66是'B'的ASCII值,65是'A'的ASCII值,是字符的存储形式)。注意,这里体现存储数据时低位在前,高位在后,低位是65,高位时66。正如十进制数98,高位时9,低位是8,所以98=9*10+8一样。因为是高位,所以乘以权位10,表示9这个符号代表的其实是90。66*256,因为存储66('B')的那一个字节的位置,比存储65('A')的那一字节的位置高8位,所以乘以2的8次方,即256。
概括讲,存储2字节的16961时,其低8位,是65,在前(x.c[0]),而其高8位,是66,在(x.c[1])。低位在前,高位在后。
请自行验证:17475=68*256+67,提现低位在前,高位在后。(x.si[1]占2字节,与x.c[2]和x.c[3]相同)。
再请验证:1145258561=17475*256*256+16961,也体现在低位在前,高位在后。(x.i占4字节,与x.si[0]和x.si[1]相同)。
再请验证:1145258561=68*256*256*256+67*256*256+66*256+65。同样的道理。