联合体(union)的使用方法和其本质

Posted beyondlpf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了联合体(union)的使用方法和其本质相关的知识,希望对你有一定的参考价值。

转自:http://blog.csdn.net/huqinwei987/article/details/23597091

 

1)联合体 union 的基本特性——和 struct 的同与不同

  union :中文名“联合体,共用体”,在某种程度上类似结构体 srtuct 的一种数据结构,union 和 struct 同样可以包含很多种数据类型和变量

  不过区别也很明显:

  struct 中所有变量是“共存”的——优点是“有容乃大”,全面;缺点是 struct 内存空间的分配是粗放的,不管用不用,全分配。

  而 union 中是各变量是 “互斥” 的——缺点就是不够 “包容” ;但优点是内存的使用更为精细灵活,也节省了内存空间。

 

2)双刃剑——多种访问内存途径共存

一个例子了然:

#include<stdio.h>

union var{
long int l;
int i;
};

int main(void)
{
union var v;

v.l = 5;
printf("v.l is %d ",v.l);

v.i = 6;
printf("now v.l is %ld! the address is %p ",v.l, &v.l);
printf("now v.i is %d! the address is %p ",v.i, &v.i);

return 0;
}

 

结果:

v.l is 5

now v.l is 6 ! the address is 0x0060fefec
now v.i is 5! the address is 0x0060fefc

 

所以说,管 union 叫共同体还真是贴切——完全就是共用一个内存首地址,并且各种变量名都可以同时使用,操作也是共同生效。如此多的access内存手段,确实好用,不过这些手段之间却没法互相屏蔽——就好像数组+下标和指针+偏移一样。

上例中我改了 v.i 的值,结果 v.l 也能读取,那么也许我还以为 v.l 是我想要的值呢,因为上边提到了 union 的内存首地址肯定是相同的,那么还有一种情况和上边类似:

一个 int 数组变量 a,一个 long int (32 位机中,long int 占 4 字节 ,与 int 相同)变量b,我即使没给变量 b 赋值,因为数据类型相同,我使用 int 变量 b 也完全会拿出 int 数组中的 a[0] 来,一些时候一不小心用上,还以为用的就是变量 b 呢 ,

这种逻辑上的错误是很难找出来的(只有当数据类型相去甚远的时候稍好,出个乱码什么的很容易发现错误);

 

3)联合体 union 和大小端(big endian , little endian):

 

#include<stdio.h>

union var{
char c[4];
int i;
};

int main(void)
{
union var data;

/* 数组中下标低的,地址也低。按地址从低到高,内存内容依次为:04,03,02,01.总共4字节 */
/* 而把四字节作为一个整体(不分类型,直接打印十六进制),应该从内存高地址到低地址看,0x01020304 */
/* 低位04放在低地址上。 */
data.c[0] = 0x04;
data.c[1] = 0x03;
data.c[2] = 0x02;
data.c[3] = 0x01;

printf("%x ", data.i);


return 0;
}

 

运行结果:

01020304

证明我的系统是小端模式( little endian )

 

4)联合体 union 所占内存空间的大小

前边说了,首先,union 的首地址是固定的,那么,union 到底总共有多大?根据一些小常识,做个不严谨不高深的基础版验证吧。

根据:内存分配空间的时候内存地址基本上是连续的,至少同类型能保证在一起,连续就说明,我如果弄三个结构体出来,他们三个地址应该连着,看一下三个地址的间隔就知道了。

#include<stdio.h>

union sizeTest{
int a;
double b;
};

int main(void)
{
union sizeTest unionA;
union sizeTest unionB;
union sizeTest unionC;

printf("the size of unionA is %d ", sizeof(unionA));
printf("the size of unionB is %d ", sizeof(unionB));
printf("the size of unionC is %d ", sizeof(unionC));

return 0;
}

运行结果:

the size of unionA is 8

the size of unionB is 8

the size of unionC is 8

 

5)联合体 union 的应用场合

有了前边的那个验证,基本可以确认, union 的内存是照着里面那个最大的那个变量分的。

也是可以大胆的推测一下,这种 union 的使用场合,是各数据类型各变量占用空间差不多并且对各变量同时使用要求不高的场合(单从内存使用上说)。

 

6)本质和进阶

根据 union 固定首地址和 union 按最大需求 开辟一段内存空间两个特征,可以发现,所有表面的定义都是虚的,所谓联合体就是在内存里面给你划了一个足够用的空间,至于你怎么玩,它不管 ~ !(何止是 union 和 struct ,C 不就是玩地址么,所以使用 C 灵活,但是也容易犯错)

没错, union 的成员变量是相当于开辟了几个接口(即 union 包含的变量)!但是,没开辟就不能用了? 当然也能用 !

写个小测试:

#include<stdio.h>

union u{
int i;
double d;
};

int main(void)
{
union u uu;
uu.i = 10;
printf("%d ",uu.i);

char *c;
c = (char *)&uu;

c[0] = ‘a‘;
c[1] = ‘b‘;
c[2] = ‘c‘;
c[3] = ‘d‘;
c[4] = ‘‘;
c[5] = ‘e‘;
c[6] = ‘f‘;
c[7] = ‘g‘;

printf("%s ",c);
for(int j = 0; j<8 ;j++)
{
printf("%c ",c[j] );
}
printf(" ");


return 0;
}

一个例子一目了然,我的结构体只定义了 int 和 double “接口”,只要获得地址,往里面扔什么数据谁管得到?这就是 C 语言的强大,这就是 union 的本质了——只管开辟一段空间。

以上是关于联合体(union)的使用方法和其本质的主要内容,如果未能解决你的问题,请参考以下文章

20160402_[转]联合体(union)的使用方法及其本质

联合体(union)的使用方法及其本质

名词解析—联合体

20160403_联合体的本质和使用 & 与struct的不同 & 大端存储和小端存储

Boost Variant 本质上是 C/C++ 中的联合?

C语言union(联合体)的使用总结