这篇博客主要介绍C++字节对齐的方式编程
什么是字节对齐数据结构
现代计算机中内存空间都是按照byte划分的,从理论上讲彷佛对任何类型的变量的访问能够从任何地址开始,但实际状况是在访问特定类型变量的时候常常在特 定的内存地址访问,这就须要各类类型数据按照必定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。架构
为何要字节对齐布局
各个硬件平台对存储空间的处理上有很大的不一样。一些平台对某些特定类型的数据只能从某些特定地址开始存取。好比有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其余平台可能没有这种状况,可是最多见的是若是不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。好比有些平台每次读都是从偶地址开始,若是一个int型(假设为32位系统)若是存放在偶地址开始的地方,那么一个读周期就能够读出这32bit,而若是存放在奇地址开始的地方,就须要2个读周期,并对两次读出的结果的高低字节进行拼凑才能获得该32bit数据。
spa
字节对齐的准则code
字节对齐的概念与规则blog
上面说的这些,百度百科上都有,而我要写的是,怎么理解上面这些东西内存
栗子一、结构体变量的首地址可以被其最宽基本类型成员的大小所整除get
struct A { double a; };
A* a=new A();
在个人机器上,a的地址上0x26e1200,能够整除double的大小8,符合准则一、结构体变量的首地址可以被其最宽基本类型成员的大小所整除编译器
栗子二、怎么计算只含基本类型成员的结构体的大小
struct A { int a; double b; char c; };
若是不考虑字节对齐,那么显然结构体A的大小为4+8+1=13。若是考虑字节对齐,咱们只须要记住两点,第1、每一个成员在结构体里的偏移都是其自身大小的整数倍,第2、结构体的总大小为最宽基本类型成员大小的整数倍
对于a,其大小为4,那么能够放在偏移为0的地方,0是4的0倍,对于b,其大小为8,能够放在偏移为8的地方,8是8的1倍,对于c能够放在偏移为16的地方,9是1的9倍,如今,结构体的大小为17,然而最宽基本类型成员是b,其大小是8,比17大的8的倍数的数字是24,因此整个结构体的大小为24
上面的栗子的布局状况像这样,灰色表明编译器为了字节对齐而填充的字节
栗子三、怎么计算含结构体的结构体的大小
struct A { int a; double b; char c; }; struct B { double a; A b; int c; };
对于含有结构体的结构体,麻烦在于咱们不知道结构体怎么算对齐值,由于偏移是根据大小来肯定的,结构体的大小是根据其本身最大基本类型成员的大小来决定的。固然,我说的不是结构体真正的大小,而是结构体计算大小,也就是上面说的对齐值。基本类型成员的对齐值就是自身大小,结构体的对齐值是本身最大基本类型成员的大小。因此在这里,a的对齐值是8,因此它应该放在偏移为0的地方,0是8的0倍,结构体b应该放在偏移为8的地方,8是8的1倍,c应该放在32的地方,32是1的32倍,如今,结构体的大小为33,然而最宽的成员大小既是a,也是结构体b,大小都是8,因此比33大的8的倍数的数字是40,整个结构体的大小为40
上面的栗子的布局状况像这样,灰色表明编译器为了字节对齐而填充的字节
栗子四、怎么计算含有指定对齐值的结构体的大小
咱们能够经过#pragma pack (value)来指定咱们想要的对齐值,结构体真正的对齐值是咱们指定对齐值和结构体自己对齐值较小的一个
#pragma pack(4)
struct A { int a; double b; char c; };
咱们已经在栗子1中见过这个结构体,这个结构体的对齐值是其自身最大的基本类型成员,也就是b,大小为8,可咱们指定的对齐的大小为4,因此这个结构的有效对齐值为4
a应该放在偏移为0的地方,0是4的0倍,b应该放在偏移为4的地方,8是4的2倍,c应该放在偏移为12的地方,12是1的12倍,如今,结构体的大小为13,比13大的4的倍数为16,因此整个结构体的大小为16
上面的栗子的布局状况像这样,灰色表明编译器为了字节对齐而填充的字节