内存对齐

why对齐?

为了提高寻址效率。
计算机内存是以字节(Byte)为单位划分的,理论上CPU可以访问任意编号的字节,但实际情况并非如此。

以32位的CPU为例,实际寻址的步长为4个字节,也就是只对编号为 4 的倍数的内存寻址,例如 0、4、8、12、1000 等,而不会对编号为 1、3、11、1001 的内存寻址。

对于程序来说,一个变量最好位于一个寻址步长的范围内,这样一次就可以读取到变量的值;如果跨步长存储,就需要读取两次,然后再拼接数据,效率显然降低了。例如一个 int 类型的数据,如果地址为 8,那么很好办,对编号为 8 的内存寻址一次就可以。如果编号为 10,就比较麻烦,CPU需要先对编号为 8 的内存寻址,读取4个字节,得到该数据的前半部分,然后再对编号为 12 的内存寻址,读取4个字节,得到该数据的后半部分,再将这两部分拼接起来,才能取得数据的值。

将一个数据尽量放在一个步长之内,避免跨步长存储,这就是所谓的内存对齐了。

内存对齐规则

以结构体为例。以下来自百度百科

1)结构体变量的首地址是其最长基本类型成员的整数倍;

2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

备注:为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。

3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。

备注:
a、结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就必须在最后填充几个字节以达到本条要求。
b、如果结构体内存在长度大于处理器位数的元素,那么就以处理器的倍数为对齐单位;否则,如果结构体内的元素的长度都小于处理器的倍数的时候,便以结构体里面最长的数据元素为对齐单位。

  1. 结构体内类型相同的连续元素将在连续的空间内,和数组一样。

举例验证

# include <iostream>
using namespace std;
struct MyStruct
{
    char b;  //1
    int a;   //4
    char d;  //1

};
int main() 
{  
    cout << sizeof MyStruct << endl; // 12
    system("pause");
    return 0;
}

对于以上程序结果为12。(1—4—1 ——>>12)
而稍微改变顺序(1—1—4 ——>>8)。
大家可以根据以上规则自己体会。

总结

(1)最后的长度一定是结构体中最长元素所占字节的整数倍。
(2)前面的地址必须是后面的地址正数倍,不是就补齐。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 首先通过一段代码来描述内存对齐的现象。 上述代码打印出来的结果为:12,8 为什么相同的结构体,只是交换了变量 a...
    xuyafei86阅读 8,102评论 2 15
  • 这几天重新看了C语言的基础知识,感觉内存对齐太重要了,应该把它记下来。个人感觉内存对齐是为了适应数据总线的宽度N,...
    SDBridge阅读 1,801评论 1 0
  • 内存对齐: 我们知道现代计算机体系中CPU按照双字、字、字节访问存储内存,并通过总线进行传输,若未经一定规则的对齐...
    null122阅读 13,144评论 12 40
  • 写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要...
    alex_zhou阅读 3,547评论 0 1
  • 在2016年,魅族因为PRO6和Pro6s的芯片问题而背上了“万年联发科”的名声,虽然魅族PRO6 Plus为魅族...
    MinCxyW阅读 3,051评论 1 0

友情链接更多精彩内容