当前位置:   article > 正文

c语言 内存对齐

c语言 内存对齐

1.前言

        内存对齐的内容CSDN论坛已经有很多人做过介绍,但是介绍场景不全,或者情形太过简单,不能满足实际研发的需要,更有甚者有许多错误。在此进行全面的介绍,如有错误,希望大家指正。

2.正文

2.1为什么要进行内存对齐

        现在CPU的主流是Intel的x86_64,虽然AMD和国产几家如飞腾海光等CPU正在崛起,但依然难以撼动Intel的垄断地位。Intel x86_64寄存器大小为64位,这意味着寄存器可以一次性读入8字节(byte),如果一个变量有4字节,但是跨了两个读入的块,就会导置一次读操作变为两次读操作,这些比较好理解,不画图赘述。

2.2内存对齐总则

***任何k字节的基本对象的地址必须是k的倍数

***结构体起始地址为内部最长基本类型的整数倍

***结构体总长度为内部最长类型的整数倍

2.2.1推论

结构体内部嵌套结构体,最长基本类型取两个结构体中最长的

内部结构体的起始位置 同样是其本身内部 最长基本数据类型的整数倍

枚举类大小默认为4字节,如果定义 其中一个元素大小超过32位 如0x1000000000, 则占8字节

2.2.2__attribute__ ((packed))

使用__attribute__ ((packed))后,结构内部地址 无空位置

__attribute__ ((aligned(4)))效果没有明显看出,有待继续研究

结构体嵌套时,外部结构体使用__attribute__ ((packed)),内部结构体自动不进行对齐

3.实例

3.1最基础场景

         现在内存系统栈是向下增长,其中a的地址其实是从6422044 ~ 6422048,即先将指向内存的指针(其实是寄存器%rsp)向下预分配int的大小的空间,然后将对应寄存器的值copy到该位置,这与内存对齐相关性不大,在此不进行赘述。结构体和数组的内存是一次性将栈指针下降整个结构体或者数组的空间,在结构体和数组内部,变量的地址是逐步增加的。

        c的地址起始为6422036,本事4字节,应该到6422040,但是b从6422043开始,说明6422041 ~ 6422043是没有使用的位置。

3.2基础结构体

总则1,任何k字节的基本对象的地址必须是k的倍数

将结构体内部的类型全修改成1 byte,结果可以看到结构体的起始位置为6422043,不为2的整数倍,说明总则2是正确的。

 

扩展成数组,可以看出该结构体的长度为5 byte,总则3

 3.3复合结构体

3.3.1结构体嵌套

 

 

 这是一个典型的结构体嵌套,st2结构体中有两个char和一个结构体,st1中一个char和一个double,整个结构体最长数据类型是8 byte。c起始地址为8整数倍,a起始地址也为8整数倍,c占一个字节,空7个字节。a占一个字节,空七个字节。这证明 结构体内部嵌套结构体,最长基本类型取两个结构体中最长的。

3.3.2 结构体内部包含枚举类

 变量en记录枚举类的起始地址,可以看出不对枚举类进行赋值,枚举类占4字节。

 给en赋值超过32位后,枚举类会扩展成为8字节

附1 结构体内部整形的排布

内部整体内存是从小到大排列,如果内部有大于一个字节的数字类型,如整形,在小端法的设备上(比如Intel x86_64),整形的内存排布是按照小端法来实现的,即如果是1,则内存排布为0x 01 00 00 00,这在指针强转的时候需要注意,例如原先是4个char,存入分别为1, 2, 3, 4。强转成int后内存中的排序是不变的,只是改了内存的解释。内存中排布为0x 01 02 03 04,用int来解释的int值为0x 04 03 02 01。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/392547
推荐阅读
相关标签
  

闽ICP备14008679号