结构体数据对齐原则的一些补充

来源:互联网 发布:原油软件 编辑:程序博客网 时间:2024/05/21 21:45

数据对齐基本原则请看上一篇博客,这里针对结构体嵌套以及结构体含有static变量的情况做一些补充:

举个例子:

一、对于node3,含有静态数据成员 

typedef struct node3{    int a;    short b;    static int c;}S3;

则sizeof(S3)=8.这里结构体中包含静态数据成员,而静态数据成员的存放位置与结构体实例的存储地址无关(注意只有在C++中结构体中才能含有静态数据成员,而C中结构体中是不允许含有静态数据成员的)。其在内存中存储方式如下:

  |--------int--------|   4字节

  |--short-|----|----|    4字节

  而变量c是单独存放在静态数据区的,因此用siezof计算其大小时没有将c所占的空间计算进来。

二、再看结构体嵌套的情况:

typedef struct node1{    int a;    char b;    short c;}S1;
typedef struct node5{    bool a;    S1 s1;    double b;    int c;}S5;
sizeof(S5)=32。

对于变量a,其自身对齐参数为1,#pragma pack(n)为8,则a的最终对齐参数为1,为它分配1字节的空间,它相对于结构体起始地址的偏移量为0,能被1整除;

  对于s1,它的自身对齐参数为4(对于结构体变量,它的自身对齐参数为它里面各个变量最终对齐参数的最大值),#pragma pack(n)为8,所以s1的最终对齐参数为4,接下来的地址相对于结构体起始地址的偏移量为1,不能被4整除,所以需要在a后面填充3字节达到4,为其分配8字节的空间;(这里不能把s1看作整体,其大小为8,所以认为对齐参数为8,结构体嵌套的情况要把结构体“打散”来看对齐参数)

  对于变量b,它的自身对齐参数为8,#pragma pack(n)的默认值为8,则b的最终对齐参数为8,接下来的地址相对于结构体起始地址的偏移量为12,不能被8整除,所以需要在s1后面填充4字节达到16,再为b分配8字节的空间;

  对于变量c,它的自身对齐参数为4,#pragma pack(n)的默认值为8,则c的最终对齐参数为4,接下来相对于结构体其实地址的偏移量为24,能够被4整除,所以直接为c分配4字节的空间。

  此时结构体所占字节数为1+3+8+4+8+4=28字节。

  对于整个结构体来说,各个变量的最终对齐参数为1,4,8,4,最大值为8,#pragma pack(n)默认值为8,所以最终结构体的大小必须是8的倍数,因此需要在最后面填充4字节达到32字节。其存储如下:

   |--------bool--------|    4字节

   |---------s1---------|    8字节

   |--------------------|     4字节

   |--------double------|    8字节

   |----int----|---------|     8字节 

  另外可以显示地在程序中使用#pragma pack(n)来设置系统默认的对齐参数,在显示设置之后,则以设置的值作为标准,其它的和上面所讲的类似,就不再赘述了,读者可以自行上机试验一下。如果需要取消设置,可以用#pragma pack()来取消。


再看一个例子:

struct A

{

short a1;

short a2;

short a3;

}A1;

struct B

{

char* a1;

char buf[5];

}B1;

struct C

{

B a;

A a2;

}C1;

sizeof(C)=20

前面说的结构体嵌套要打散,并不是说把C变成这样

struct C

{

char* a1;

char buf[5];

short a1;

short a2;

short a3;

}C1;

然后sizeof(C)=16=4+5+1(填充)+2+2+2

打散是为了找最大对齐字节数。

首先a的起始地址为0a作为结构体,为其分配的大小为12,这时候把a2“打散,求最大对齐字节数为sizeof(short)=2,12能整除2,所以a2的起始地址为12,再给a2分配6个字节内存,这样总共有12+6=18个字节,对于整个结构体C来说,各个变量的最终对齐参数为41222,最大值为4,所以最终结构体的大小必须是4的倍数,因此需要在最后面填充2字节达到20字节。

其存储如下:

|------char*--------|    4字节

|------char[5]------|     5字节

|-------------------|     3字节

|--------short------|    2字节

|--------short------|    2字节

|--------short------|    2字节

|----------|           2字节


0 0