您的位置:首页 > 编程语言 > C语言/C++

对《C语言:内存字节对齐详解——struct 和 union 》的理解

2013-10-22 21:32 746 查看
本文是对先前转载的一篇C语言:内存字节对齐详解/article/8615504.html的学习和理解,主要以一个例子来分析,首先还是重新提一下理解这个例子的必备知识:

对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,其自身对齐值为4,double类型,其自身对齐值为8,单位字节。

这里面有四个概念值:

1)数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值。

2)指定对齐值:#pragma pack (value)时的指定对齐值value。

3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。

4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。

有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是
数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整 数倍,结合下面例子理解)。

下面以我自己写的一个例子程序来具体分析(基于Win 7 32位系统):

#include <stdio.h>

struct A{

char a;

short b;

double c;

int d;

};

struct B{

char e;

A a;

};

void main()

{

printf("%d %d",sizeof(A),sizeof(B));

}

运行结果为:24 32

sizeof(A)的结果分析:根据上面所说的,可以简单假设struct A{ }的第一个成员 char a的存储首地址为0x0000,对于char型数据,其自身对齐值为1,并且char型数据分配1个字节的内存;接着是short,其自身对齐值为2,也就是说该数据的"存放起始地址%2=0,所以该数据存储在0x0002~0x003(short型数据分配内存2个字节);然后是double
c,double型自身对齐值为8,所以该数据存储在0x0008~0x000f(该数据的"存放起始地址%8=0);接着是int d,int型自身对齐值为4,所以可以连续存储在0x0010~0x0013(该数据的"存放起始地址%8=0);最后结构体自身为了保持圆整,会以成员中"有效对齐N"最大的8进行对齐,可以将这段内存看成是连续的(在这里会延伸到0x0017),中间空的地方用0填充,及考虑内存地址对齐之后struct
A的占用的内存单元是0x00~0x17共24个字节;

接着分析struct B,同样假设,将char e存放在0x00,由对sizeof(A)的结果分析可以知道,struct A 以8字节对齐,(还是假设以一段连续的内存单元来存储)所以,A a的存储首地址为0x08~0x1f(注意A a 实际占用24个字节),然后用0填充,所以共32个字节。

注意:如果结构体中有数组,只需将数组看成若干个相同的单个同类型的数据,例如,将char a 改成char a [5],怎可当成是连续定义了5个char型数据。

说完了struct ,接下来再说一下 union,首先摘几句The C Programming Language里面讲述这个问题的原话:

①联合就是一个结构

②它的所有成员相对于基地址的偏移量都为0

③此结构空间要大到足够容纳最“宽”的成员

④并且,其对齐方式要适合于联合中所有类型的成员。

附图说明:



该结构要放得下int i[5]必须要至少占4×5=20个字节。如果没有double的话20个字节够用了,此时按4字节对齐。但是加入了double就必须考虑double的对齐方式,double是按照8字节对齐的,所以必须添加4个字节使其满足8×3=24,也就是必须也是8的倍数,这样一来就出来了24这个数字。综上所述,最终联合体的最小的size也要是所包含的所有类型的基本长度的最小公倍数才行。(这里的字节数均指win
32位下的值,平台、编译器不同值也有可能不同。)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: