C/C++:内存对齐(struct/union/field)
原因
? 字节对齐主要是为了提高内存的访问效率。
对齐原则
-
首个成员在与结构体变量偏移量为0的地址处 -
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间 -
变量对齐数 = Min(编译器默认对齐数,该成员大小) -
各成员变量对齐到自身对齐数的整数倍(嵌套结构体对齐到自身最大对齐数整数倍) -
结构体总大小为所有最大对齐数(包含嵌套结构体的成员对齐数)的整数倍
示例
1.不同顺序排列
? S1大小:12字节(1+3 +4 + 1+3);
? S2大小:8字节(1+1+2 + 4);
? 粗体为对齐填充字节。
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
char c2;
char c1;
int i;
};
2.包含数组
? student大小:24(10+2+4+1+3+4)
? char name[10] 的本质是 10 个 char 变量,所以就把它当成 10 个 char 变量看就行了;
? 粗体为对齐填充字节。
struct student
{
char name[10];
int age;
char sex;
float score;
};
3.结构体嵌套
? student大小:32(4+13+7+8)
? st1大小:48(4+4+32+1+7)
struct student
{
int num;
char name[13];
double gender;
};
struct st1
{
int age;
struct student s1;
char sex;
};
4.联合体嵌套
? 联合体对齐方式要适合其中所有的成员(整个大小为最大对齐数的整数倍)
? MyUnion大小:16(13+3)
? st1大小:32(4+4+16+1+7),union1应按成员最大字节对齐数(8)对齐,整个结构体为double倍数
union MyUnion
{
int num;
char name[13];
double gender;
};
struct st1
{
int age;
union MyUnion union1;
char sex;
};
pragma指令
- 使用伪指令#pragma pack (n),C编译器将按照**min(n, sizeof(a))**个字节对齐(a为某类型变量,n= 1,2,4,8,16)。
- 使用伪指令#pragma pack (),取消自定义字节对齐方式。
示例
1.S1大小:6(1+1+4)
? S2大小:10(1+1+6+2),嵌套时按照min(2,sizeof(a))对齐
#pragma pack(2)
struct S1 {
char a;
long b;
};
struct S2 {
char c;
struct S1 d;
char e;
};
#pragma pack()
2.S1大小:8(1+3+4)
? S2大小:16(1+3+8+1+3),嵌套时按照min(8,sizeof(a))对齐
#pragma pack(8)
struct S1 {
char a;
long b;
};
struct S2 {
char c;
struct S1 d;
char e;
};
#pragma pack()
位域
位域的声明和结构是类似的,有两个不同:
示例
? 连续相同类型可使用位域来节省空间(S1)
? 连续不同类型需按照对齐规则分配空间(S2)
? 含位域的结构体嵌套对齐规则与普通嵌套相同(S3)
struct S1 {
int i:8;
int b:4;
char a:3;
double c;
};//16字节
struct S2 {
int i:8;
char a:3;
int b : 4;
double c;
};//24字节
struct S3 {
char c;
struct S2 d;
char e;
};// 40字节
|