6.8 联合
联合是可以(在不同时刻)保存不同类型和长度的对象的变量,编译器负责跟踪对象的长度和对齐要求
联合提供了一种方式,以在单块存储区中管理不同类型的数据,而不需要在程序中嵌入任何同机器有关的信息
它类似于 Pascal 语言中的变体记录
类比 TypeScript 中声明多种类型的情况
如:let a: string | number | Person = ‘test’;
我们来看一个例子(可以在编译器的符号表管理程序中找到该例子)
假设一个常量可能是 int
、f1oat
或字符指针
特定类型的常量值必须保存在合适类型的变量中
然而,如果该常量的不同类型占据相同大小的存储空间,且保存在同一个地方的话,表管理将最方便
这就是联合的目的 —— 一个变量可以合法地保存多种数据类型中任何一种类型的对象
其语法基于结构:
union u_tag {
int ival;
float fval;
char *sval;
} u;
变量 u
必须足够大,以保存这 3 种类型中最大的一种,具体长度同具体的实现有关
这些类型中的任何一种类型的对象都可赋值给 u
,且可使用在随后的表达式中,但必须保证是一致的:读取的类型必须是最近一次存入的类型
程序员负责跟踪当前保存在联合中的类型
如果保存的类型与读取的类型不一致,其结果取决于具体的实现
可以通过下列语法访问联合中的成员:
联合名.成员
或 联合指针->成员
它与访问结构的方式相同
如果用变量 utype
跟踪保存在 u
中的当前数据类型,则可以像下面这样使用联合:
if (utype == INT)
printf("%d\n", u.ival);
if (utype == FLOAT)
printf("%f\n", u.fval);
if (utype == STRING)
printf("%s\n", u.sval);
else
printf("bad type %d in utype\n", utype);
联合可以使用在结构和数组中,反之亦然
访问结构中的联合(或反之)的某一成员的表示法与嵌套结构相同
例如,假定有下列的结构数组定义:
struct {
char *name;
int flags;
int utype;
union {
int ival;
float fval;
char *sval;
} u;
} symtab[NSYM];
可以通过语句 symtab[i].u.ival
引用其成员 ival
也可以通过下列语句之一引用字符串 sval
的第一个字符:
*symtab[i].u.sval
symtab[i].u.sval[0]
实际上,联合就是一个结构,它的所有成员相对于基地址的偏移量都为 0
此结构空间要大到足够容纳最 “ 宽 ” 的成员,并且,其对齐方式要适合于联合中所有类型的成员
对联合允许的操作与对结构允许的操作相同:作为一个整体单元进行赋值、复制、取地址及访问其中一个成员
联合只能用其第一个成员类型的值进行初始化,因此,上述联合 u
只能用整数值进行初始化
第 8 章的存储分配程序将说明如何使用联合来强制一个变量在特定类型的存储边界上对齐