联合体
联合体是一种用户定义的类型,由位于同一内存区域的字段组成,原因是这些字段相互重叠。这样就可以将一种类型的值写入联合体,然后在另一种类型的解释中读取其内部表示(位级)。因此,我们可以提供从一种类型到另一种类型的非标准转换。
联合体字段可以是任何内置类型,但字符串、动态数组和指针除外。此外,在联合体中,可以使用具有相同简单字段类型且不带构造函数/析构函数的结构体。
编译器会为联合体分配一个内存单元,其大小等于所有元素类型的最大大小。因此,对于具有 long(8 字节)和 int(4 字节)等字段的联合体,将分配 8 字节。
联合体的所有字段都位于相同的内存地址,即在联合体的起始位置对齐(偏移量为 0,可以使用 offsetof 进行检查,参见 打包结构体一节)。
描述联合体的语法与描述结构体类似,但使用的是 union 关键字。它的后面是一个标识符,然后是一个包含字段列表的代码块。
例如,某种算法可能会使用 double 类型的数组来存储各种设置,只因为 double 类型是最大字节数等于 8 的类型之一。假设设置中有诸如 ulong 的数字。由于 double 类型不能保证准确再现较大的 ulong 值,因此需要使用联合体将 ulong“打包”到 double 中,然后再“解包”回来。
#define MAX_LONG_IN_DOUBLE 9007199254740992
|
ulong2double 结构体的大小等于 8,因为它的两个字段都具有此大小。因此,字段 U 和 D 完全重叠。
就整数而言,9007199254740992 是 double 类型能够可靠存储的最大精确整数值。在本例中,我们尝试用 double 来多存储一个数字。
从 ulong 到 double 的标准转换会造成精度损失:将 9007199254740993 写入 double 类型的变量 d 后,我们读取到的值是经过“舍入”的值 9007199254740992(有关以 double 类型存储数字的更多细节,请参见 实数一节)。
使用转换器时,数字 9007199254740993 将“原样”地写入联合体,无需转换,因为我们将其赋值给 ulong 类型的 U 字段。该数字的 double 表示可从字段 D 中获得,同样没有经过转换。我们可以放心地将其复制到其他变量和数组(如 double)。
虽然生成的 double 值看起来很奇怪,但如果需要通过反向转换提取,它与原始整数完全匹配:写入 double 类型的 D 字段,然后从 ulong 类型的 U 字段读取。
联合体可以包含构造函数和析构函数,也可以包含方法。默认情况下,联合体成员具体公共访问权限,不过可以像在结构体中那样,使用访问修饰符进行调整。