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

结构体类型(一般方式和位域存储方式)的sizeof

2014-03-06 19:18 281 查看
结构体在内存中的存放是按照字节对齐来实现存放的

什么是对齐,以及为什么要对齐: 
    现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 
对齐的作用和原因:

    各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为
32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。

 

1)一般结构体 

结构体存储遵循下述两点规则:

整体空间是结构体内占用空间最大的成员的宽度的整数倍
数据对齐原则---内存按结构体内成员的先后顺序排列,每一个成员摆放的初始位置都必须是该成员类型所占内存宽度的整数倍,如果不够就向后偏移,直到补齐到最近的整数倍位置。(内存存储位置是从0开始算的,int从0,4,8这样的位置算起,char任何位置OK,double从0,8,16等这样的位置算起)

ex:

struct S1
{
int i;   //(4个字节)
char c;   //(1个字节)
double d;   //(8个字节)
};  //16个字节


int从4的整数倍位置开始存放,所以第一个位置0合适,char从1的整数倍开始存放,需一个字节,所以存在第五位上合适,double需要在8的整数倍位置上存储,而距离5最近的就是8号位置,所以char之后偏移3个字节再存放double,所以总共需要的内存数为4+1+3+8=16字节,double最宽共8字节,16为8的两倍,符合规则1。int从0开始,char从5开始,double从8开始,符合规则2。

struct S2
{
int i;   //(4个字节)
double d;   //(8个字节)
char c;   //(1个字节)
};    //24个字节

int从4的整数倍位置开始存放,所以第一个位置0合适,double需要在8的整数倍位置上存储,而距离4最近的就是8号位置,所以int之后偏移4个字节再存放double,那么char起始位置为16,符合1的整数倍,这时所有成员排下来共占用4+4+8+1=17个字节位置,不是max(4,8,1)=8的整数倍,所以在后续需要空出7个字节的位置来填补,所以总共需要的内存数为4+4+8+1+7=24字节,double最宽共8字节,24为8的两倍,符合规则1。int从0开始,double从8开始,char从16开始,符合规则2。

2) 对于以位域方式存储的结构体:

      注:位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof。成员的位域值不能超过其类型的字节宽度,否则可能要报错,比如int型的,其位域在范围[1,32]中,short在[1,16]中,char都可以,不是所有的类型都能够用位域表示。

规则:

如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
如果位域字段之间穿插着非位域字段,则不进行压缩;
整个结构体的总大小为最宽基本类型成员大小的整数倍。  
ex:

struct S3
{
short a:1;   //(1bit)
char b:7;   //(7bit)
short d:1;   //(1bit)
};    //6个字节

首先,short是2个字节,从2的整数倍开始存放,那么0位置是合适的,然后是char类型,和short是不同的类型,这是在VC6中,所以根据第三条,采取不压缩方式,那么short仍然是要占用2个字节宽度(位域为1,然后补齐15个位域位置,凑够2个字节=2*8位),char从第2个字节处开始存储,需要7bit的位置,小于一个字节,但是第三个为short,其应该从0,2,4这样的位置开始存放,所以在char之后要补齐到4字节的位置,即补9个bit位置,那么这样下来共需存储空间为1bit+15bit+7bit+9bit+1bit=33bit,但是根据5,整体大小应该为最宽基本类型(short)的整数倍,所以应该是2字节的整数倍,那么离33bit最近的整数倍字节为6字节=48bit,所以补齐到48bit位置,故而整个结构体总的存储空间为6字节=48bit

struct S4
{
int a:1;   //(1bit)
int b:7;   //(7bit)
int d:1;   //(1bit)
};    //4个字节
首先,int是4个字节,所以a应从4的倍数开始存放,0符合条件,第二个仍为整形,和第一个一样,所以可以采取压缩的方式,直接放在第1个bit位置上,第三个仍然为int,可以放在第(1+7-1)个位置上,但由于int的宽度为4个字节,所以应该要补全到4个字节位置上,这时整的存储空间是4个字节。

struct S5
{
int a:1;   //(1bit)
int b;   //(4个字节)
int d:1;   //(1bit)
};    //12个字节


中间穿插非位域形式的时候,就不压缩,第一个1个字节,是从0位置开始,合适,第二个就应该从4的整数倍位置开始,而不是连在第一个位置后面,所以第一个后面应填补31个bit,第三个的话放在8字节位置处,是4的整数倍,这样总体是65个bit,不是4字节的整数倍,所以最后补充31个bit,这样总体就是12个字节了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息