C语言中的sizeof(struct )和sizeof(union)

时间:2022-09-05 16:08:07

一般32位机上各数据类型所占存储空间为:

char : 8位

short : 16位

int : 32位

long : 32位

float : 32位

double : 64位


一、结构体struct 

1.在没有#pragma pack 宏的情况下:

三条原则:

(1)数据成员对齐规则:(原则1)

结构体struct的数据成员,第一个数据成员放在offset为0的地方,之后每个数据成员的起始位置要从该成员大小的整数倍开始。(比如int在32位机上要从4的整数倍开始存储) 。

(2)结构体作为成员 :(原则2)

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

(3)结构体的大小 :(原则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】……【23】,(原则3

}BB;

typedef struct aa {

char name[2] ;  //【0】,【1】

int  id ; //【4】……【7】原则1

double  score ;  //【8】……【15】

short  grade ; //【16】,【17】

BB  b;  //【24】……【47】原则2因为BB内部最大成员为double,即8的整数倍开始存储

}AA;


则:

int  main(void)
{
printf("sizeof(BB) = %d\nsizeof(AA) = %d\n", sizeof(BB), sizeof(AA));

return 0;
}


得到结果为:

sizeof(BB) = 24
sizeof(AA) = 48

但是,如果在Linux环境下,使用gcc得到结果为

sizeof(BB) = 16
sizeof(AA) = 36

想想为什么?!!

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


2.有#pragma  pack(n)

#pragma pach(n)来设置变量以n字节对齐方式,其中n为1、2、4、8、16,n字节对齐就是变量存放的起始位置的偏移量有两种情况:

(1)若n大于等于变量所占字节数 , 偏移量必须满足默认的字节对齐方式,即变量所占字节数的整数倍

(2)若n小于变量所占字节数,偏移量为n的整数倍,不用满足默认的对齐方式。

因此,结构体的大小分两种情况:

(1)若n大于所有成员类型所占字节数,那么结构的总大小必须为占用的空间最大的变量占用的空间的倍数。

(2)否则,必须为n的倍数

所以,在上面的代码上加上#pragma pack(1),得到bb :(0~3)+(4~11)+(12~15) = 16

  aa  : (0~1)+(2~5)+(6~13)+(14~15)+(16~31) = 32

即#pargma pack(1)就是没有对齐规则。

但是,若加上#pragmg pack (4)得到结果为bb : (0~3)+(4~11)+(12~15) = 16

    aa :  (0~1)+(4~7)+(8~15)+(16~17)+(20~35) = 36


二、union共用体(联合体)

几个变量共用一个内存位置,在不同的世家保存不同的数据类型和不同长度的变量,当一个共用体被声明时,编译程序会自动产生一个变量,其长度为联合体中元类型(如素族,取类型长度)最大的变量长度的整数倍,且要大于等于最大成员所占的存储空间。

例如:

 union foo{

char s[10] ;

int  i ;

};

其中,foo的内存空间长度为12,是int型数据的3倍,并不是数组长度10,若把int改成double,则foo的空间为16,是double的2倍。

例如:

union  mm{

char a;//1字节

int b[5] ;//20字节

double  c ; //8字节

int d[3] ; //12字节

};

则sizeof(union mm) = 8*3 = 24 ;


另外:

当共用体包含结构体时

struct inner{

char c1;

double d;

char c2;

];

union data4{

struct inner t;

int  i;

char c;

};

由于data4共用体中有inner结构体,所以节本数据类型为double,8字节对齐。共用体长度取决于t,所以sizeof(union data4) = 24


当结构体中含有共用体,共用体里的对其地址为共用体本身内部所对齐的位数。

typedef  union {

long i ;

int  k[5];

char c;

}DATE;

struct  data{

int cat ;

char cc;

DATE cow;

char a[6];

};

则sizeof(DATE) = 20 , 在结构体中:4+1+3(补齐4对齐)+20+6+2(补齐4对齐) = 36