一般而言,需满足三个准则:
1.结构体变量的首地址能够被最宽基本类型成员的大小所整除
2.结构体每个成员相对于结构体首地址的偏移量都是当前成员大小的整数倍,如有需要编译器会在成员之间加上填充字节
3.结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后填充字节
说明:
1.基本类型是指前面提到的像 char short int float double 这样的内置数据类型
2.对于复合数据类型,如结构体嵌套结构体,那么基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型
3.我认为计算结构体大小的时候,主要用到准则2和准则3,对于准则1是编译器自动完成的,不需要过多理会
4.C++中类可以看做特殊的结构体,所以类的sizeof的计算和结构体是一样的
下面结合前面给出的准则具体分析一下:
1 #include “stdafx.h” 2 #include<iostream> 3 4 using namespace std; 5 6 struct A 7 { 8 char a; 9 int b; 10 }; 11 struct B 12 { 13 char a; 14 A al; 15 char b; 16 }; 17 18 19 int main(int argc,char* argv[]) 20 { 21 cout<<sizeof(A)<<endl<<sizeof(B); 22 return 0; 23 }
对于结构体A 其基本成员类型有char和int 两种 最宽的是int 占用4个字节 根据准则1,编译器自动为结构体A分配一个能被4整除的首地址,A的第一个成员char的首地址就是结构体A的首地址,接下来,下一个成员变量int首地址,如果不做处理的话,应该是相对于A的偏移量是1,这就不满足准则2了,所以编译器开始在char后面填充3个字节,使得int相对于A的偏移量是4,来满足准则2 然后结构体A的总大小就是:1(插入)+3(填充)+4(int).
对于结构体B 其中包括了一个符合类型,查看基本类型的时候,要将其中的结构体A拆分成char和int两种类型来看,所以结构体B中的基本数据类型就是char char int char 最宽的数据类型是int ,编译器会自动为B分配一个能被4整除的首地址,B的第一个成员char的首地址就是结构体B的首地址,接下来,下一个成员变量A的首地址,如果不做处理的话,应该是相对于B的偏移量是1,这就不满足准则2了,所以编译器开始在char的后面填充3个字节使得成员A相对于所在结构体B的地址偏移量是4,来满足准则2,这时加上A的长度8,B的最后一个成员char相对于B来说地址偏移量是12,能满足准则2,所以不需要在A的后面填充字节,这时B的总长度是1(char)+3(填充)+8(A)+1 =13 不满足准则3,所以还需要在最后一个char后面再添加3个字节,所以最后B的总长度为13+3 = 16.