内存对齐、内存补齐
2017-08-06 00:25
113 查看
1 引言
记得第一次接触这块知识是在3月底海康威视春招嵌入式岗位面试的时候。那时候面试官问了我一个问题:问下面代码所占字节的大小。struct str{ int a; char b; }
当时对内存对齐与补齐也不太懂,直接说了一句int类型占4个字节,char类型占1个字节,总共占5个字节。当时面试官也没说对错。后来回来和室友讨论才知道还要考虑内存补齐。所以在32位系统中一共要占8个字节。
最近恰好在牛客网刷题时候又遇到了这个问题,所以彻底学习了一下。
2 内存对齐、补齐
许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址是某个数k(通常要求为4或8的倍数),这就是所谓的内存对齐。2.1 内存对齐规则
struct或者union成员对齐规则:1、第一个数据成员放在offset为0的地方,对齐按照对齐系数和自身所占用的字节数中,两者比较小的那个进行对齐。
2.2 内存补齐规则
在struct或者union数据成员完成各自对齐之后,struct或者union本身也要对齐,对齐按照对齐系数和struct或者union中最大数据成员长度中比较小的那个进行。先局部成员对齐,然后再全局对齐。2.3 对齐的优点
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
3 例题讲解
这是一个摘自牛客网的例题:struct One{ double d; char c; int i; } struct Two{ char c; double d; int i; }
问在#pragma pack(4)和#pragma pack(8)的情况下,结构体的大小分别是多少?
答:首先在#pragma pack(4)情况下,按照内存对齐的原则,struct One中的d占据0-7字节(offset=0开始,double类型占8个字节)。第二个成员c占据8字节(char类型占1个字节,对齐系数是4,两者中1较小,所以偏移地址必须是1的倍数,最近的1的倍数是8,所以i从8开始占1个字节)。第三个成员i占据12-15字节(int类型占4个字节,对齐系数是4,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是12,所以i从12开始占4个字节,前面的9-11三个字节对齐。)。而struct One中最大的数据成员是double型,占8个字节,对齐系数是4,两者中4较小,内存补齐的的地址必须是4 的倍数,而下一个字节刚好是16,是4的倍数,所以不需要内存补齐。所以在#pragma pack(4)情况下,struct One所需内存为16字节。
struct Two中的c占据0字节(offset=0开始,char类型占1个字节)。第二个成员d占据4-11字节(double类型占8个字节,对齐系数是4,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是4,所以i从4开始占8个字节,前面的1-3三个字节对齐。)。第三个成员i占据12-15字节(int类型占4个字节,对齐系数是4,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是12,所以i从12开始占4个字节)。而struct Two中最大的数据成员是double型,占8个字节,对齐系数是4,两者中4较小,内存补齐的的地址必须是4 的倍数,而下一个字节刚好是16,是4的倍数,所以不需要内存补齐。所以在#pragma pack(4)情况下,struct Two所需内存为16字节。
在#pragma pack(8)情况下,按照内存对齐的原则,struct One中的d占据0-7字节(offset=0开始,double类型占8个字节)。第二个成员c占据8字节(char类型占1个字节,对齐系数是8,两者中1较小,所以偏移地址必须是1的倍数,最近的1的倍数是8,所以i从8开始占1个字节)。第三个成员i占据12-15字节(int类型占4个字节,对齐系数是8,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是12,所以i从12开始占4个字节,前面的9-11三个字节对齐。)。而struct One中最大的数据成员是double型,占8个字节,对齐系数是8,两者中8较小,内存补齐的的地址必须是8 的倍数,而下一个字节刚好是16,是8的倍数,所以不需要内存补齐。所以在#pragma pack(8)情况下,struct One所需内存为16字节。
struct Two中的c占据0字节(offset=0开始,char类型占1个字节)。第二个成员d占据8-15字节(double类型占8个字节,对齐系数是8,两者中8较小,所以偏移地址必须是8的倍数,最近的8的倍数是8,所以i从8开始占8个字节,前面的1-7七个字节对齐。)。第三个成员i占据16-19字节(int类型占4个字节,对齐系数是8,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是16,所以i从16开始占4个字节)。而struct Two中最大的数据成员是double型,占8个字节,对齐系数是8,两者中8较小,内存补齐的的地址必须是8 的倍数,而下一个字节是20,不是8的倍数,所以需要内存补齐。最近的8的倍数是24,所以需要再补4位,即占用20-23字节用来结构体内存补齐。所以在#pragma pack(8)情况下,struct Two所需内存为24字节。
4 自测题
在32位机器上,下列代码中sizeof(a)的值是()class A { int i; union U { char buff[13]; int j; }u; void foo(){} typedef char* (*f)(void*); enum{red,green,blue}color; }a;
答案是24=4+13+3+0+0+4。其中成员函数不管是否为空,都不会占用空间,有虚函数除外,有虚函数时会多一个指针(内存+4);typedef是声明,不占用空间;枚举则是int,占4个字节。
相关文章推荐
- sizeof内存对齐和虚指针内存布局
- 谈谈关于内存对齐与补齐
- 内存对齐与补齐 字节对齐与结构体大小
- 内存对齐与ANSI C中struct型数据的内存布局 选择自 soloist 的 Blog
- 谈谈关于内存对齐与补齐
- 内存对齐与补齐
- 内存对齐全攻略--涉及位域的内存对齐原则
- 深入理解sizeof+C语言数据类型+内存补齐
- struct对象在内存中所占的空间大小(内存对齐)
- C++内存补齐
- C++内存 内存对齐
- 深入理解sizeof+C语言数据类型+内存补齐
- 内存对齐是什么?为什么要内存对齐?
- 结构体内存大小的求法(内存对齐)&&c++类大小同样适用
- C/C++中的内存补齐机制
- C++内存 内存对齐
- 谈谈关于内存对齐与补齐
- 深入理解sizeof+C语言数据类型+内存补齐
- 初学者对于结构体内存对齐与补齐的理解
- 内存对齐(补齐)