这可能是因为你使用的编译器的原因,导致了结构体和联合体的内存对齐方式不同。内存对齐是一种优化内存访问速度的技术,它会根据数据类型的大小来调整数据在内存中的位置,使得数据的起始地址是它的大小的整数倍。例如,如果一个int类型的数据占4个字节,那么它的起始地址应该是4的整数倍,比如0,4,8,12等。如果一个char类型的数据占1个字节,那么它的起始地址可以是任意的,比如0,1,2,3等。内存对齐的好处是可以提高内存访问的效率,但是也会造成一些内存空间的浪费。
在你的代码中,你定义了一个结构体类型CharAndInt,它包含了一个int类型的成员data和一个char类型的数组s[5]。你定义了一个联合体类型CharOrInt,它也包含了一个int类型的成员data和一个char类型的数组s[5]。在我的编译器中,结构体和联合体的内存对齐方式是这样的:
// 结构体类型CharAndInt的内存布局
| data | s[0] | s[1] | s[2] | s[3] | s[4] |
| 0 | 4 | 5 | 6 | 7 | 8 |
// 联合体类型CharOrInt的内存布局
| data | s[0] | s[1] | s[2] | s[3] | s[4] |
| 0 | 0 | 1 | 2 | 3 | 4 |
可以看到,结构体类型CharAndInt的大小是9个字节,因为它的最后一个成员s[4]的地址是8,加上它的大小1,就是9。联合体类型CharOrInt的大小是5个字节,因为它的最大的成员是s[5],它的大小是5。所以,我的输出结果是:
CharAndInt占用9个字节
CharOrInt占用5个字节
但是,在你的编译器中,结构体和联合体的内存对齐方式可能是这样的:
// 结构体类型CharAndInt的内存布局
| data | s[0] | s[1] | s[2] | s[3] | s[4] |
| 0 | 4 | 5 | 6 | 7 | 8 |
| | | | | | |
| | | | | | |
// 联合体类型CharOrInt的内存布局
| data | s[0] | s[1] | s[2] | s[3] | s[4] |
| 0 | 0 | 1 | 2 | 3 | 4 |
| | | | | | |
可以看到,结构体类型CharAndInt的大小是12个字节,因为它的最后一个成员s[4]的地址是8,加上它的大小1,再加上3个字节的空白,就是12。联合体类型CharOrInt的大小是8个字节,因为它的最大的成员是s[5],它的大小是5,再加上3个字节的空白,就是8。所以,你的输出结果是:
CharAndInt占用12个字节
CharOrInt占用8个字节
这就是为什么你的输出结果和我预测的不一样的原因。内存对齐的方式取决于编译器的设置,不同的编译器可能有不同的内存对齐规则