一、结构体的对齐规则:
编译环境: vs2017
1.结构体的第一个数据成员在偏移量为0的地址处。
2.其他成员放在对齐数的整数倍地址处。
对齐数取编译器默认和该数据成员大小的min,vs默认值是8,Linux没有默认对齐数。
3.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,也就是max(成员变量大小)。(这条规则对应问题分析中的蓝色字体)
4.结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
用一些小例子演示一下:
例一:
struct s1
{
double a;
char b;
int c;
};
printf("%d\n", sizeof(struct s1));
下面分析这道题:
数据成员对齐数 = min( 编译器默认对齐数,该数据类型大小 )
1. double a; // 地址从0开始,前8个字节存的是double
2. char b; // min(8 ,1) = 1 ,此时下标是8,8是1的整数倍,第9个字节存的是char
3. int c; // min(8,4) = 4 ,此时下标是9,9不是4的整数倍,补3个字节,此时下标是12,存入int
4.共存了8+4+4=16个字节,整体对齐系数 = min(8,max( double, char, int )) = 8,16是8的整数倍,不用补空字节,分析完成。
综上所述,该结构体占有16个字节。
例二:
struct s2
{
char a;
struct s1 s11;
double b;
};
printf("%d\n", sizeof(struct s2));
分析这道题:
数据成员对齐数 = min( 编译器默认对齐数,该数据类型大小 )
1. char a; // 地址从0开始,第一个字节存的是char
2. struct s1 s11; // min( 8 ,max(double,char,int)) = 8 ,此时下标是1,1不是8的整数倍,补7个空字节,再存入s11(16个字节)
3. double b; // min(8,8) = 8 ,此时下标是24,24是8的整数倍,再存入double
4. 共存了1+7+16+8=32个字节,整体对齐数 = min( 8,max( char, struct s1, double )) = 8,32是8的整数倍,不用补空字节,分析完成。
综上所述,该结构体占有32个字节。
二、修改默认对齐数:
预处理指令: #pragma
例三:
struct s1
{
double a;
char b;
int c;
};
#pragma pack(4)
struct s2
{
char a;
struct s1 s11;
double b;
};
#pragma pack()
int main()
{
printf("%d\n", sizeof(struct s1));
printf("%d\n", sizeof(struct s2));
system("pause");
return 0;
}
题目分析:
s1在上面例一已经分析过,这里主要分析s2
数据成员对齐数 = min( 修改后的默认对齐数(4) ,该数据类型大小 )
1. char a; // 地址从0开始,第一个字节存的是char
2. struct s1 s11; // min( 4 ,max(double,char,int)) = 4 ,此时下标是1,1不是4的整数倍,补3个空字节,再存入s11(16个字节)
3. double b; // min(4,8) = 4 ,此时下标是20,20是4的整数倍,再存入double
4. 共存了1+3+16+8=28个字节,整体对齐数 = min(4,max( char, struct s1, double )) = 4,28是4的整数倍,不用补空字节,分析完成。
综上所述,该结构体占有28个字节。