内存字节对齐、为何要对齐

内容会持续更新,有错误的地方欢迎指正,谢谢!web

内存字节对齐

对齐的三个原则

如何内存对齐?sizeof的结果怎么来的?请记住如下3条原则:(在没有#pragma pack宏的状况下)数组

  1. 原则1:结构(struct)或联合(union)的数据成员,存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,好比说是数组,结构体等)的整数倍开始(好比:假设一个数据成员为int,int在32位机上为4字节,则要从4的整数倍地址开始存储)
  2. 原则2:若是一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(好比:struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储)
  3. 原则3:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

内存字节对齐的缘由

根本缘由在于CPU访问数据的效率问题。好比有些平台每次读都是从偶地址开始,若是一个int型(假设为32位系统)若是存放在偶地址开始的地方,那么一个读周期就能够读出这32bit,而若是存放在奇地址开始的地方,就须要2个读周期,并对两次读出的结果的高低字节进行拼凑才能获得该32bit数据。显然在读取效率上降低不少。svg

举例1

typedef struct bb
{
    int id;            //0~3
    double weight;     //8~15 原则1
    float height;      //16~19 要为8的整数倍,补齐20~23 原则3
}BB;

typedef struct aa
{
 char name[2];     //0~1 申请了两个char空间,因此是占用2个字节
 int  id;          //4~7 原则1
 double score;     //8~15
 short grade;      //16~17    
 BB b;             //24~47 要从8的整数倍开始存 原则2
}AA;

int main()
{
  AA a;
  cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
  return 0;
}

结果是48 24spa

举例2

在32位cpu上选择缺省对齐的状况下,有以下结构体定义:code

struct A
{
    unsigned a : 19;//后面的数字表示bit
    unsigned b : 11;
    unsigned c : 4;
    unsigned d : 29;
    char index;//1个字节=8bit
};

则sizeof(struct A)的值为?xml

解答:由32位缺省对齐,因此有:
因为19+11=30<32,19和11算做32位,即4个字节
因为4+29>32,4算做32位,即4个字节
因为29+8>32,29算做32位,即4个字节
因为8<32,8算做32位,即4个字节blog

因此,总共有16个字节!sizeof(struct A)的值为16。图片

用pragma控制内存对齐

再讲讲#pragma pack():在代码前加一句#pragma pack(1),你会发现上面的代码输出为32 16,由于bb是4+8+4=16,aa是2+4+8+2+16=32。这不就是理想中的没有内存对齐的世界嘛。内存

下面的代码,在#pragma pack(4)#pragma pack(8)的状况下,结构体的大小分别是:string

struct One{  
    double d;  
    char c;  
    int i;  
}  
struct Two{  
    char c;  
    double d;  
    int i;  
}

这里写图片描述

因此,答案为16,16,16,24