一般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