转载:https://www.linuxidc.com/Linux/2019-01/156153.htm (结构体与联合体的分析比较)
共用体(联合体) / union
有时,我们需要使几种不同类型的变量存放到 同一段 内存单元中。例如,可以把一个整型变量(2 个字节)、一个字符型变量(1 个字节)、一个实型变量(4 个字节)放在 同一开始地址 的内存单元中,如下图所示:
以上 3 个变量在内存中占的字节数不同,但都从同一地址开始存放,也就是几个变量相互覆盖。这种使几个不同的变量共占同一段内存的结构,称为 “共用体” 类型的结构,也称为 “联合体” 。
共用体变量的定义
定义共用体类型变量的一般形式为:
union 共用体名 { 成员列表 } 变量列表;
例如:
union data { int i; char c; float f; } a, b, c;
也可以将类型声明与变量的定义分开:
union data { int i; char c; float f; }; union data a, b, c;
即先声明一个 union data
类型,再将 a, b, c
定义为 union data
类型。此外,也可以省略共用体名直接定义共用体变量:
union { int i; char c; float f; } a, b, c;
可以看到,“共用体”与“结构体”的定义形式相似,但它们的含义是不同的:
- 结构体变量所占的内存长度(字节总数)是各成员占的内存长度之和,每个成员都分别独占其自己的内存单元。
- 共用体变量所占的内存长度等于 最长 的成员的长度。例如上述定义的共用体变量
a, b, c
各占 4 个字节(因为其中最长的实型变量占 4 个字节),而不是各占 2+1+4=7 个字节。
共用体变量的引用
与结构体类似,共用体变量中成员的引用方式为:
共用体变量名.成员名
只有先定义了共用体变量才能引用它,而且不能直接引用共用体变量,只能引用共用体变量中的成员。例如,前面定义了共用体变量 a
,则:
a.i
表示引用共用体变量中的整型变量i
a.c
表示引用共用体变量中的字符型变量c
a.f
表示引用共用体变量中的实型变量f
但不能只引用共用体变量,例如 printf("%d", a);
是错误的,因为 a
的存储区有好几种类型,分别占不同长度的字节,仅写共用体变量名 a
,难以使系统确定究竟输出的哪一个成员的值。
共用体类型数据的特点
在使用共用体类型数据时,应当注意以下一些特点:
-
同一个内存段可以用来存放几种不同类型的成员,但在 每一瞬时只能存放其中一种 ,而 不是同时存放几种 。也就是说,每一瞬时只有一个成员起作用,其它的成员不起作用,即:共用体中的成员不是同时都存在和起作用的。
-
共用体变量中起作用的成员是 最后一次 存放的成员,在存入一个新的成员后,原有的成员就失去作用了。例如有如下赋值语句:
a.i = 1; a.c = 'F'; a.f = 2.5;
在执行完以上 3 条赋值语句后,此时只有 a.f
是有效的,而 a.i
和 a.c
已经无意义了。因此在引用共用体变量的成员时, 程序员 自己必须十分清楚当前存放在共用体变量中的究竟是哪个成员。
-
共用体变量的地址和它的各成员的地址都是同一地址,例如
&a
、&a.i
、&a.c
、&a.f
都是同一个地址值,其原因是显然的。 -
不能直接对共用体变量名赋值,也不能企图引用变量名来得到一个值,同时也不能在定义共用体变量时对它初始化。例如,以下这些都是不对的:
union { int i; char c; float f; } a = {1, 'a', 1.5}; // 不能对共用体初始化 a = 1; // 不能对共用体变量赋值 m = a; // 不能引用共用体变量名以得到一个值
-
不能把共用体变量作为函数参数,也不能使函数返回共同体类型的变量,但可以使用指向共用体变量的指针(与结构体变量的指针用法类似,不再赘述)。
-
共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
共用体总感觉像是计算机发展早期,内存寸土寸金的遗留产物。