各种sizeof



结构体的对齐

sizeof计算一个结构体的大小时,经常得到的值比结构体内部成员所占内存总和要大,这就是因为在结构体内部,成员在存储时有对齐的规则。结构体对齐指的是:编译器向结构体插入无用内存的能力,插入无用内存使得结构体成员以最佳方式对齐,从而得到更高的效能。当基本数据类型以字节地址(几倍于自身大小)存储时,很多处理器能够获得最佳效能。

以下是几个例子:

Struct x

{

     Shorts;//2 bytes   and 2 padding tytes

     Inti;  //4 bytes

     Charc; //1 bytes   and 3 padding bytes

};

Struct y

{

     Inti;    //4 bytes

     Charc ;  //1 bytes   and 1 padding byte

     Shorts;  //2 bytes

};

Struct z

{

     Inti;    //4 bytes

     Shorts;  // 2 bytes

     Charc;   //1 bytes  and 1 padding byte

};

Sizeof(x)=12;   sizeof(y)=8;    sizeof(z)=8;

X的内存布局:  s             I             c

                11**          1111          1***

Y的内存布局:  I             c             s

                1111          1*            11

Z的内存布局:   I             s             c

                1111           11            1*

其中*表示填充的字节,xs后面为什么要填充两个字节?因为i是整型,其起始位置要为4的倍数。C后面要填充3个字节,因为结构体size要为4(即最大类型——整型sizeof(int))的倍数。

YC后面填充一个字节,因为sshort类型,起始位置要为2的倍数。S后面没有填充,因为cs正好占用了4个字节。

Zs后面没有填充,因为sc正好占用4个字节,c填充一个字节因为struct大小要为int的整数倍。

再看一个有结构体作为成员的例子:

Struct A

{

     Int a;

     Double b;

     Float c;

};

Struct B

{

     Char e[2];

     Int f;

     Double g;

     Short h;

     Struct A I;

};

Sizeof(A)=24; 因为 int4double8float4,总长为8的倍数,补齐,所以为24Sizeof(B)=48;看一下B的布局

B的内存布局:e        f         g         h                     i

            11**    1111     11111111   11******    1111****, 11111111,1111****

I其实就是A的内存布局。I的起始位置要为24的倍数,所以h后面要补齐(A的最大类型是double,占8个字节,所以i开始要8字节对齐,即8的倍数,所以h要填充)。

通过把最大的数据类型放在结构体的开始,最小数据类型放在结构体的最后,这样可以得到最小的结构体size

通过上面的例子可以总结一下三个规律:

数据成员对齐,结构体(或联合体)的数据成员,第一个数据成员放在offset0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int32位机为4字节,则要从4的整数倍地址开始存储)。

结构体作为成员,如果一个结构体里面有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(struct b里面有struct aa里面有charintdouble等元素,那么a应该从8的整数倍开始存储)。

结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐








union u
{
 double a;
 int b;
}; 


union u2
{
 char a[13];
 int b;
}; 


union u3
{
 char a[13];
 char b;
}; 

union u4
{
double i;
char k;
int m[5];
};

cout<<sizeof(u)<<endl; // 8
cout<<sizeof(u2)<<endl; // 16
cout<<sizeof(u3)<<endl; // 13
cout<<sizeof(u4)<<endl; // 24
   都知道union的大小取决于它所有的成员中,占用空间最大的一个成员的大小。所以对于u来说,大小就是最大的double类型成员a了,所以 sizeof(u)=sizeof(double)=8。但是对于u2和u3,最大的空间都是char[13]类型的数组,为什么u3的大小是13,而 u2是16呢?关键在于u2中的成员int b。由于int类型成员的存在,使u2的对齐方式变成4,也就是说,u2的大小必须在4的对界上,所以占用的空间变成了16(最接近13的对界)。 






 sizeof和含有位域的结构体的使用: 
位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。
C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,
允许其它类型类型的存在。
使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字
段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字
段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。 
让我们来看如下的例子:
struct stu{
char a:3;
char b:4;
char c:5;
}; 
则sizeof(struct stu)的大小在gcc上面得到的结果为2,在visual c上得到的结果也为2。根据以上五条,还有前面讲的对齐,可以得出结果为2个字节。我们再来看下如下的例子: 
struct stu{
char a:3;
int b:4;
char c:5;
};
则sizeof(struct stu)的大小在gcc上面得到的结果为4,在visual c上得到的结果为12。根据以上五条,还有前面讲的对齐,可以推出这样的结果,请着重看下第三条,就可以知道visual c和gcc分别得到不同结果的原因了。  
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值