联合体大小由最大成员决定并按最高对齐要求对齐。例如,包含int(4字节,对齐4)和double(8字节,对齐8)的联合体大小为8字节,因其需满足double的对齐要求。当联合体含结构体或数组时,结构体自身大小受其成员对齐影响,如Struct{char;short;}通常占4字节,故union{int;struct{char;short;}}大小为4。含char[10]和int的联合体因需对齐到4或8的倍数,大小可能为12或16。通过sizeof可验证联合体大小,如union{int;double;char[15];}在多数编译器下为16字节,因需容纳15字节数组并对齐到8字节边界。#pragma pack可控制对齐但影响移植性。
联合体的大小取决于其最大的成员的大小。 也就是说,联合体的大小至少要能够容纳其最大的成员。
联合体在内存中分配一块足以容纳其最大成员的空间。所有成员都共享同一块内存区域。因此,在任何给定的时间,联合体只能存储一个成员的值。理解联合体大小的计算方法对于优化内存使用和避免潜在的错误至关重要。
联合体大小计算中的对齐规则是什么?
对齐规则是影响联合体大小的重要因素。编译器会对联合体的大小进行对齐,使其为联合体中对齐要求最高的成员的倍数。这意味着即使联合体中最大的成员的大小不是某个特定值的倍数,联合体的大小也会被填充到该值的倍数。
举个例子,假设一个联合体包含一个
int
(4 字节,对齐要求为 4) 和一个
double
(8 字节,对齐要求为 8)。 即使
double
是最大的成员,大小为 8 字节,联合体的大小也需要是 8 的倍数。 因此,联合体的大小将是 8 字节。
再看一个稍微复杂点的例子:
union ExampleUnion { char a; // 1 字节 int b; // 4 字节 double c; // 8 字节 }; sizeof(ExampleUnion); // 在大多数编译器上,结果是 8
在这个例子中,
double c
是最大的成员,大小为 8 字节,对齐要求也为 8。 因此,整个联合体的大小就是 8 字节。
考虑以下情况:
union AnotherUnion { char a; // 1 字节 int b; // 4 字节 long long c; // 8 字节 char d[3]; // 3 字节 }; sizeof(AnotherUnion); // 在大多数编译器上,结果是 8
尽管
long long c
是最大的成员,大小为 8 字节,但是
char d[3]
的存在并没有改变联合体的大小。 因为联合体只需要能够容纳最大的成员即可,而
long long
已经满足了这个条件。
联合体中包含结构体或数组时如何计算大小?
当联合体包含结构体或数组时,大小计算会变得稍微复杂一些。在这种情况下,需要考虑结构体或数组本身的大小,以及它们对联合体整体对齐的影响。
例如,假设一个联合体包含一个
int
和一个结构体,该结构体包含一个
char
和一个
short
。 结构体的大小将受到对齐的影响,可能大于其成员大小的总和。
看下面的例子:
struct ExampleStruct { char a; // 1 字节 short b; // 2 字节 }; union UnionWithStruct { int x; // 4 字节 ExampleStruct y; // 结构体大小受对齐影响 }; sizeof(ExampleStruct); // 结果可能是 4,因为 short 通常需要 2 字节对齐 sizeof(UnionWithStruct); // 结果可能是 4
在这个例子中,
ExampleStruct
的大小可能是 4 字节,因为
short b
通常需要 2 字节对齐。 因此,
UnionWithStruct
的大小将是 4 字节,因为
int x
和
ExampleStruct y
的大小都是 4 字节。
再看一个包含数组的例子:
union UnionWithArray { int a; // 4 字节 char b[10]; // 10 字节 }; sizeof(UnionWithArray); // 结果可能是 12 或 16,取决于对齐要求
在这个例子中,
char b[10]
是最大的成员,大小为 10 字节。 但是,联合体的大小可能需要对齐到 4 字节的倍数(因为
int a
的存在),因此联合体的大小可能是 12 字节。 如果编译器对联合体有更高的对齐要求(例如 16 字节),那么联合体的大小就会是 16 字节。
如何通过代码验证联合体的大小?
可以通过
sizeof
运算符来验证联合体的大小。 这是一个非常有用的工具,可以帮助你理解编译器如何处理联合体的内存布局。
以下是一个简单的 c++ 代码示例,演示如何使用
sizeof
运算符来验证联合体的大小:
#include <iostream> union MyUnion { int a; double b; char c[15]; }; int main() { MyUnion u; std::cout << "Size of MyUnion: " << sizeof(u) << std::endl; // 输出联合体的大小 return 0; }
这段代码会输出
MyUnion
的大小。 在大多数编译器上,结果应该是 16,因为
double
是最大的成员,大小为 8 字节,并且
char c[15]
大小为15字节,需要对齐到 8 的倍数。
还可以使用
#pragma pack
指令来控制结构体和联合体的对齐方式。 但是,使用
#pragma pack
可能会导致代码在不同的编译器上表现不一致,因此应该谨慎使用。