结构体内存对齐
struct S1
{
char c1;//第一个成员,从零开始0
int i;//对齐数4的倍数,从4开始到5,6,7,浪费1,2,3
char c2;//对齐数1的倍数,占据8的位置,此时结构体大小为9,但是结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍,所以再扩充到11的位置
};
printf("%d\n", sizeof(struct S1));//是6吗?
//答案12,涉及知识点结构体内存对齐
首先得掌握结构体的对齐规则:
-
第一个成员在与结构体变量偏移量为0的地址处。
-
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
Linux中没有默认对齐数,对齐数就是成员自身的大小
-
结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
-
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
//练习-结构体嵌套问题
struct S3
{
double d;//0到7,对齐数8
char c;//占据8,对齐数1
int i;//浪费9,10,11的位置,占据12,13,14,15的位置,但结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。此时大小为16,无需扩充
};
struct S4
{
char c1;//0号位置
struct S3 s3;//对齐数为8,根据如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
//浪费1到7的位置,占据从8到15的位置
double d;//对齐数为8,占据16的位置一直到21,此时结构体总大小22,扩充到32
};
printf("%d\n", sizeof(struct S4));//32
位段的练习
位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构体(联合体)称为位段结构。采用位段结构既能够节省空间,又方便于操作。
-
位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
-
位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
-
位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
//练习
int main()
{
unsigned char puc[4];
struct tagPIM
{
unsigned char ucPim1;
unsigned char ucData0 : 1;
unsigned char ucData1 : 2;
unsigned char ucData2 : 3;
}*pstPimData;
pstPimData = (struct tagPIM*)puc;
memset(puc,0,4);
pstPimData->ucPim1 = 2;
pstPimData->ucData0 = 3;
pstPimData->ucData1 = 4;
pstPimData->ucData2 = 5;
printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);//02 29 00 00
return 0;
}