结构体内存对齐 & 联合体大小计算

本文详细解析了结构体内存对齐的规则及原因,包括对齐数的计算与修改,以及联合体的定义与大小计算。通过具体实例,展示了不同编译环境下结构体与联合体的对齐方式,帮助理解内存对齐对性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:结构体内存对齐规则

  • 1.第一个成员在结构体变量偏移量为0的地址处。

  • 2.从第二个成员变量开始,要对齐到对齐数的整数倍 地址处。
    对齐数 就是 编译器默认的一个对齐数 与 该成员大小中的 较小的那一个。

    • VS编译器默认的对齐数是8(字节), Linux中默认对齐数是4
  • 3.结构体总大小 是每个成员变量的对齐数 中最大的对齐数的整数倍。

  • 4 如果结构体中嵌套了另外一个结构体,那么就把这个嵌套在里面的结构体当成外面结构体的一个成员,里面的结构体的对齐到自己的最大对齐数的整数倍,(这时里面的结构体也有一个最大对齐数,把这个对齐数就当做里面的结构体的对齐数),所以整体大小就是最大对齐数的整数倍。

  • 注意:32位平台下,vs的默认对齐数是4字节,但是在64位平台下,vs的默认对齐数是8字节。

二:内存对齐的大小计算

在这里插入图片描述

如何修改默认对齐数:

修改默认对齐数: 使用 #pragma pack(n)
恢复默认对齐数: 使用 #pragma pack()

修改默认对齐数后的结构体大小:
在这里插入图片描述

//穿插一个结构体只是验证
struct S
{
	float f;  //4   ---4
	short s;   //2    ---2(4)
	int i;     //4    ----4
	double d;    //8  ----8(4+8)
	char c;   //1      ----1
	int a[4];  //16   ----16(3+16) 
			                  //4+4+4+12+1+19=44,  结构体大小应该是48,经过验证,结果正确
};


struct B
{
	float f;  //4   ---4
	short s;   //2    ---2(4)
	int i;     //4    ----4
	char c;   //1      ----1
	char a[7];  //7   ----7  ---对齐数是1,不是7,说明了数组的对齐数是对应元素的类型大小,而不是数组的大小
							  //4+4+4+1+7=20,  结构体大小应该是20,经过验证,结果正确
};


int main()
{
	int a[4];
	cout << sizeof(S) << endl;    //40
	cout << sizeof(B) << endl;    //20

	cout << sizeof(float) << endl;   //4
	cout << sizeof(short) << endl;   //2
	cout << sizeof(double) << endl;  //8
	cout << sizeof(a) << endl;      //16
	return 0;
	}

三:结构体内存对齐原因

为什么要有结构体内存对齐?
原因:
(1)方便移植,因为不是所有的硬件平台都能任意访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则会抛出硬件异常。
(2)有利于性能的提升,如果内存没有对齐,处理器需要做两次内存访问;而对齐的内存的访问仅需要一次。所以数据结构应该尽可能的在自然边界上对齐。
(3)内存对齐实质上是一种以空间换区取时间的做法,因此在设计结构体的时候,应该既要满足对齐,又要节省空间,可以采取让占用空间小的成员尽可能的其中在一起。



联合体(共用体)

1.定义:

联合体是一种特殊的自定义类型,联合体变量包含一系列成员,这些成员公用同一份内存空间

//联合体的声明
union Un
{
		int a;
		char b;
}

//联合体的定义
union Un un;   //un就是联合体变量

//计算联合体大小
printf("%d\n",sizeof(un));

2.联合体大小的计算规则:

满足以下两点:

  • 联合体的大小 >= 最大成员的大小
  • 当最大成员大小不是最大对齐数的整倍数时, 要对齐到最大对齐数的整数倍(对齐的结果是超过并接近最大成员大小)。
例如:求联合体Un1的大小?在这里插入图片描述
分析:

1.变量c 是个短整型数组,有七个元素,大小是14字节,vs编译器默认的对齐数是8字节,所以两者最终的对齐数(取较小的对齐数作为变量的对齐数)是8字节。
2.变量i 是个整型变量,大小是4字节,vs编译器默认的对齐数是8字节,所以最终变量i的对齐数是4字节。
3.所以,整个共用体的最大对齐数为变量c的对齐数----8。但是考虑到最大成员的大小14不是8的倍数,所以要对齐到8的整数倍----16。

### 结构体内存对齐的基本原理 C语言中结构体内存布局并不是简单地按照成员变量的顺序连续排列,而是受到**内存对齐规则**的影响。内存对齐的主要目的是提高CPU访问内存的效率,尤其是在访问未对齐的数据时可能会导致性能下降或硬件异常。 结构体对齐规则包括以下几点: 1. **成员变量的起始地址必须是其类型对齐数的整数倍**。例如,`int` 类型通常要求其起始地址是4的倍数。 2. **结构体的总大小必须是其所有成员变量中最大对齐数的整数倍**。如果最后的填充不够,则会在结构体末尾添加填充字节。 例如,考虑以下结构体: ```c struct MyStruct { int a; // 4字节 char b; // 1字节 int c; // 4字节 }; ``` 该结构体内存布局如下所示: ``` +-------+-------+-------+-------+-------+-------+-------+-------+ | a | a | a | a | b | pad1 | pad2 | pad3 | +-------+-------+-------+-------+-------+-------+-------+-------+ | c | c | c | c | | | | | +-------+-------+-------+-------+-------+-------+-------+-------+ ``` - `int a` 占用4字节,起始地址为0,符合对齐要求。 - `char b` 占用1字节,起始地址为4,符合对齐要求。 - `int c` 需要4字节对齐,但由于 `b` 后面只有1个字节,不足以满足 `int` 的对齐要求,因此在 `b` 后面插入3个填充字节。 - 结构体大小必须是 `int` 类型(最大成员)对齐数的整数倍,即8字节的整数倍。最终大小为8字节 + 4字节 = 12字节[^2]。 --- ### 结构体对齐与填充示例 以下是一个更直观的例子: ```c struct Example { char a; // 1字节 int b; // 4字节 short c; // 2字节 }; ``` 根据对齐规则,其内存布局如下: ``` +-------+-------+-------+-------+-------+-------+-------+-------+ | a | pad1 | pad2 | pad3 | b | b | b | b | +-------+-------+-------+-------+-------+-------+-------+-------+ | c | c | pad4 | pad5 | | | | | +-------+-------+-------+-------+-------+-------+-------+-------+ ``` - `char a` 占1字节,起始地址为0,符合对齐要求。 - `int b` 需要4字节对齐,因此在 `a` 后面填充3个字节。 - `short c` 需要2字节对齐,当前地址为8,刚好是2的整数倍,无需填充。 - 结构体大小为12字节,是最大成员(`int`)对齐数的整数倍[^2]。 --- ### 联合体内存对齐 联合体(union)的内存大小取决于其最大成员的大小,并且需要对齐到该最大成员的对齐数。例如: ```c union example3 { float x; // 4字节 char c[5]; // 5字节 } w; ``` 该联合体的最大成员是 `char c[5]`,其大小为5字节。但由于联合体对齐要求为4字节(`float` 的对齐数),最终联合体大小为8字节(向上取整到4的整数倍)[^1]。 --- ### 内存对齐的图示总结 以下是一个结构体内存布局图示: ``` struct MyStruct { int a; // 4字节 char b; // 1字节 int c; // 4字节 }; ``` 对应的内存布局为: ``` +-------+-------+-------+-------+-------+-------+-------+-------+ | a | a | a | a | b | pad1 | pad2 | pad3 | +-------+-------+-------+-------+-------+-------+-------+-------+ | c | c | c | c | | | | | +-------+-------+-------+-------+-------+-------+-------+-------+ ``` - `a` 占用4字节,地址为0。 - `b` 占用1字节,地址为4。 - `c` 需要4字节对齐,因此在 `b` 后面插入3个填充字节。 - 结构体大小为12字节,是最大成员对齐数(4)的整数倍[^2]。 --- ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值