牛骨文教育服务平台(让学习变的简单)
博文笔记

C当中关于sizeof(struct)和sizeof(union)

创建时间:2013-06-07 投稿人: 浏览次数:189

一般32位机子上各个数据类型所占的存储空间如下:

char:8位 

short:16位

int:32位

long:32位

float:32位

double:64位

一、接下来先来看struct,结构体

请牢记以下3条原则:(在没有#pragma pack宏的情况下)

1、数据成员对齐规则:结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,之后的每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机子上为4字节,所以要从4的整数倍地址开始存储)。

2、结构体作为成员:如果一个结构体里同时包含结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(如struct a里有struct b,b里有char,int ,double等元素,那么b应该从8(即double类型的大小)的整数倍开始存储)。

3、结构体的总大小:即sizeof的结果。在按之前的对齐原则计算出来的大小的基础上,必须还得是其内部最大成员的整数倍,不足的要补齐(如struct里最大为double,现在计算得到的已经是11,则总大小为16)。

具体例子:

typedef struct bb
{
	int id;             //[0]....[3]      表示4字节
	double weight;      //[8].....[15]      原则1
	float height;      //[16]..[19],总长要为8的整数倍,仅对齐之后总长为[0]~[19]为20,补齐[20]...[23]     原则3
}BB;
typedef struct aa  
{  	
	int  id;         //[0]...[3]          原则1  
	double score;     //[8]....[15]      
	short grade;    //[16],[17]          
	BB b;             //[24]......[47]       原则2(因为BB内部最大成员为double,即8的整数倍开始存储)  
	char name[2]; //[48][49]
}AA; 

int main()
{
	cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl;
	return 0;
}
输出结果为56 24

以上结果是在没有#pragma pack(n)宏的情况下,现在来讲讲关于#pragma pack(n)。

编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。//n为1、2、4、8、16...

n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,即该变量所占用字节数的整数倍;第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。

所以在上面的代码前加一句#pragma pack(1),

则代码输出为bb:(0~3)+(4~11)+(12~15)=16;aa:(0~1)+(2~5)+(6~13)+(14~15)+(16~31)=32,也就是说,#pragma pack(1)就是没有对齐规则。

再考虑#pragma pack(4),bb:(0~3)+(4~11)+(12~15)=16;aa:(0~1)+(4~7)+(8~15)+(16~17)+(20~35)=36

二、union共用体(联合)

共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。当一个共用体被声明时, 编译程序自动地产生一个变量, 其长度为联合中元类型(如数组,取其类型的数据长度)最大的变量长度的整数倍,且要大于等于其最大成员所占的存储空间。
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。