字节对齐问题
概念:
CPU每一次读取数据是按照固定起始地址和字节长度读取的
比如32位(4字节)的CPU读取起始地址为0x0000,那么其读取数据地址顺序应该是0x0000~0x0003,然后0x0004~0x0007
当有个4字节数据存储在0x0002~0x0005上,即起始地址为0x0002,为了读取完整,CPU需要分别读取0x0000~0x0003和0x0004~0x0007,这样一个字节的数据读取就进行了两个字节的CPU读取,效率低且浪费资源。
假如该数据存储为0x0000或0x0004甚至0x0008,CPU只需要分别以0x0000或0x0004或0x0008为起始地址读取一次即可,不难看出,其由CPU的固定起始地址和数据存放起始地址的相对位置有关,其量化表示可为:数据存放起始地址能被字节长度所整除,则效率最大化。如例子中0x0002 % 4 = 2,明显不整除,而如果数据存储在如0x0004或0x0008为起始地址,则可以整除。
结构体的对齐规则:
按最大类型的倍数
首地址为自身大小的倍数
这里解释下为什么需要按最大类型的倍数,如下例子
struct MyStruct1 { char b; // 本来1个字节 + 7个字节padding double a; // 8 个字节 int c; // 本来 4 个字节,但是整体要按 8 字节对齐,所以 4个字节padding // 总共: 8 + 8 + 8 = 24 };
之所以int c后要按最大的double的8字节进行填充,是因为考虑到多个结构体实例的对齐,加入int c后不补充,则单个结构体的占用为0x00~0x14(假如从0x00开始)共二十个字节,那么如果有下一个结构体就是从0x15开始,
该结构体内部的字节排布则是
char b : 0x15~0x1D
double a : 0x1E~xxx,可以看到此时类型为double的a变量的首地址无法被8整除(0x1E=0d30,30无法被8整除)
操作(这里仅讨论向下对齐):
使用“与”操作抹去相对高位。如0d0033即0b00100001,对于4字节对齐则与上~(0x0003)即抹除不到整4的值,得到0d0032;对于8字节对齐则与上~(0x0007)即抹除不到整8的值,得到0d0032,以此类推
参考:
https://blog.csdn.net/Demondai999/article/details/121640212
http://t.zoukankan.com/grooovvve-p-14158927.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通