数据对齐那些事

来源:互联网 发布:雷特字幕mac 编辑:程序博客网 时间:2024/05/16 12:39

前言

目前的操作系统主要有32位和64位,也就是说机器字长是32位和64位。在计算硬件底层,CPU是按一个传送单位(32/64位)进行存取,而且是按字节进行编址。数据对齐指的是计算机系统对基本数据类型合法地址做出了一些限制,要求某种类型对象的地址必须是某个值K(2,4,8)的倍数。为什么要进行对数据对齐,我们可以看看下面的例子:
假设在一个32位的系统中,有int i; short k; double x; char c; short j; 几个变量,如果我们不进行数据对齐的话,存放这5个变量需要17个字节,而当我们想要访问变量x的时候需要3个指令周期,而访问j需要2个指令周期。如果进行数据对齐的话,虽然需要20字节存放变量,访问变量x需要2个指令周期,访问j则只需1个周期。

数据对齐 数据对齐情况下

数据不对齐 数据不对齐情况下

从上面分析可以看出,数据对齐虽然浪费了存储空间,但是提高了执行速度,在现代操作系统中存储空间并不是瓶颈,所以一般的操作系统都会进行数据对齐。

数据对齐规则

每个特定平台上的编译器都有自己默认的“对齐系数”,可以通过预编译命令#pragma pack(n),n=1,2,4,6,8,16来改变这一系数,其中n就是你要指定的对齐系数。

数据对齐规则如下:

  1. 结构体或联合体中数据成员对齐规则:第一个数据成员放在offset为0的地方,以后每个数据成员对齐按照#pragma pack指定的数值和这个数据成员自身长度中的比较小的那个进行。
  2. 结构体或联合体整体对齐规则:在数据成员完成各自对齐之后,结构体和联合体本身也要进行对齐,对齐按照#pragma pack指定的数值和结构体或联合体中最大数据成员长度中的比较小的那个进行。
  3. 由1,2可知,当#pragma pack的n值等于或超过所有数据成员的长度的时候,这个n值的大小将不产生任何效果,数据成员都会按照自己的长度进行对齐。

数据对齐实战

考虑下面的结构声明,确定每个字段的偏移量,结构的总大小,以及在linux下32位下的对齐要求(4字节)。

struct P1{    int i;    char c;    int j;    char d;}p1;struct P2{    int i;    char c;    char d;    int j;}p2;struct P3{    short w[3];    char c[3];  }p3;struct P4{    short w[3];    char *c[3]; }p4;struct P5{    struct P1 a[2];    struct P2 *p;}p5;

分析: 在p1中,p1.i的大小在32位机器为4字节跟起始的对齐系数相同,故i以4字节方式进行对齐,所以p1.i应该放在离结构体首地址偏移量offset为0的地方,所占区间为[0,3]。变量c的大小为1字节<4,按照1字节对齐,放在offset=4的地方[4,5]。变量j的大小为4字节=4,按照4字节对齐,因对齐要求,需要char c后面插入3字节的一个空隙,将j放在offset=8的地方,所占区间为[8,11]; 变量d的大小为1字节,按照1字节对齐,放在offset为12的地方,所占区间为[12,13]。为了满足结构体整体的对齐要求,结构体最大成员长度大小为4字节=4,需要按4字节对齐,所以需要在char d后面再插入3字节的空隙,所以整体结构体的大小为16字节,按照4字节对齐。剩下的p2~p5都可以按照上述方式进行计算,得到结果如下:

这里写图片描述

程序验证:

#include <iostream>using namespace std;struct P1{    int i;    char c;    int j;    char d;}p1;struct P2{    int i;    char c;    char d;    int j;}p2;struct P3{    short w[3];    char c[3];  }p3;struct P4{    short w[3];    char *c[3]; }p4;struct P5{    struct P1 a[2];    struct P2 *p;}p5;int main(){    cout<<sizeof(p1)<<endl;    cout<<sizeof(p2)<<endl;    cout<<sizeof(p3)<<endl;    cout<<sizeof(p4)<<endl;    cout<<sizeof(p5)<<endl;}

上述代码使用32位编译器进行编译得到的结果如下:

这里写图片描述

在64位编译进行编译将得到如下,结果可自行分析.

这里写图片描述

原创粉丝点击