C++字节对齐

这篇博客主要介绍C++字节对齐的方式编程

什么是字节对齐数据结构

现代计算机中内存空间都是按照byte划分的,从理论上讲彷佛对任何类型的变量的访问能够从任何地址开始,但实际状况是在访问特定类型变量的时候常常在特 定的内存地址访问,这就须要各类类型数据按照必定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。架构

为何要字节对齐布局

各个硬件平台对存储空间的处理上有很大的不一样。一些平台对某些特定类型的数据只能从某些特定地址开始存取。好比有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其余平台可能没有这种状况,可是最多见的是若是不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。好比有些平台每次读都是从偶地址开始,若是一个int型(假设为32位系统)若是存放在偶地址开始的地方,那么一个读周期就能够读出这32bit,而若是存放在奇地址开始的地方,就须要2个读周期,并对两次读出的结果的高低字节进行拼凑才能获得该32bit数据。
spa

字节对齐的准则code

其实字节对齐的细节和具体编译器实现相关,但通常而言,知足三个准则:
1) 结构体变量的首地址可以被其最宽基本类型成员的大小所整除;
2) 结构体每一个成员相对于结构体首地址的偏移量都是成员大小的整数倍,若有须要编译器会在成员之间加上填充字节;例如上面第二个结构体变量的地址空间
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,若有须要编译器会在最末一个成员以后加上填充字节。

字节对齐的概念与规则blog

四个基本概念

1.数据类型自身的对齐值:
  对于char型数据,其自身对齐值为1,对于short型为2,对于int,float类型,其自身对齐值为4,对于double型,其自身对齐值为8,单位字节。
  2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
  3.指定对齐值:#pragma pack (value)时的指定对齐值value。
  4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。

对齐规则

有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的前后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放,结构体自己也要根据自身的有效对齐值圆整。

上面说的这些,百度百科上都有,而我要写的是,怎么理解上面这些东西内存


栗子一、结构体变量的首地址可以被其最宽基本类型成员的大小所整除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

上面的栗子的布局状况像这样,灰色表明编译器为了字节对齐而填充的字节