结构体的内存空间分配及字节对齐

本文详细探讨了结构体中内存空间分配的规则,通过实例解释了如何计算结构体的大小,强调了字节对齐的重要性。同时,推荐了一篇深入讨论结构体字节对齐的优质博客资源。
关于内存对齐
一:
1.什么是内存对齐
假设我们同时声明两个变量:
char a;
short b;
用&(取地址符号)观察变量a,
b的地址的话,我们会发现(以16位CPU为例):
如果a的地址是0x0000,那么b的地址将会是0x0002或者是0x0004。
那么就出现这样一个问题:0x0001这个地址没有被使用,那它干什么去了?答案就是它确实没被使用。因为CPU每次都是从以2字节(16位CPU)或是4字节(32位CPU)的整数倍的内存地址中读进数据的。如果变量b的地址是0x0001的话,那么CPU就需要先从0x0000中读取一个short,取它的高8位放入b的低8位,然后再从0x0002中读取下一个short,取它的低8位放入b的高8位中,这样的话,为了获得b的值,CPU需要进行了两次读操作。

但是如果b的地址为0x0002,那么CPU只需一次读操作就可以获得b的值了。所以编译器为了优化代码,往往会根据变量的大小,将其指定到合适的位置,即称为内存对齐(对变量b做内存对齐,a、b之间的内存被浪费,a并未多占内存)。

2.结构体内存对齐规则
结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下:
(1)每个成员分别按自己的对齐字节数和PPB(指定的对齐字节数,32位机默认为4)两个字节数最小的那个对齐,这样可以最小化长度。
(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。
(3)结构体对齐后的长度必须是成员中最大的对齐参数(PPB)的整数倍,这样在处理数组时可以保证每一项都边界对齐。
(4)计算结构体的内存大小时,应该列出每个成员的偏移地址,则其长度=最后一个成员的偏移地址+最后一个成员数的长度+最后一个成员的调整参数(考虑PPB)。

结构体是C/C++等编程语言中的一种用户自定义数据类型,它可以包含不同类型的数据成员。了解结构体内存空间分配对于优化程序性能、减少内存浪费至关重要。 ### 结构体内存对齐 在大多数平台上,并不是所有的CPU都能高效地访问任意地址处的数据,某些特定类型的变量需要存储在指定字节边界上才能提高读取效率,这就是所谓的**内存对齐**(Memory Alignment)。编译器会按照一定的规则自动调整各个字段之间的间距以及整个struct最后的实际大小: 1. **每个成员相对于结构体起始位置的偏移量都是该成员自身长度的最大公约数倍数** 2. **结构体总尺寸为所有元素中最长的那个基本单位整数倍** 例如,在32位系统下,默认4字节对齐的情况下,一个简单的`struct Point { int x; char y; float z }`将会这么布局: ``` | int (x) |char(y)|padding(3B)|float(z) | 0 4 5 8 12 ``` 这里我们看到为了保证浮点型z处于合适的偏移地址上,不得不插入了三个填充字节(`padding`)使得y到z之间有足够的间隔;同样地,在最后一个成员之后也可能存在额外的空间以确保整体满足某种对齐约束。 ### 自定义控制对齐方式 有时默认设置可能导致不必要的开销,此时可通过预处理指令改变当前翻译单元内的对齐属性,比如GCC/G++支持使用 `#pragma pack(n)` 来设定新的打包级别n(一般设为1即可消除空隙),或者利用标准C11关键字 `_Alignas()` 指定单个域的具体界限条件。 #### 示例代码片段展示不同情况下的实际占用差异: ```c++ #include <iostream> using namespace std; #pragma pack(push,1)//保存原有状态并切换至一字节模式 struct PackedStruct { char a; double b; }; #pragma pack(pop)//恢复原先设定 int main() { cout << "Normal Struct Size: " << sizeof(struct NormalStruct) << "\nPacked Struct Size:" << sizeof(PackedStruct); } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值