原因:
结构体内存对齐是因为,对于计算机来说读取4个字节的内存空间比读取1、2、3个字节的要更高效。但是也根据编译器而定,而且自己也可以改变对齐内存的大小用 预编译命令#pragma pack (n)
规则:
1.第一个元素offset偏移到地址为0的内存上。
2.之后的元素对齐到对齐数大小的整数倍的偏移量上。
何为对齐数:对齐系数和元素大小的较小值,每个成员变量除了第一个成员都有对齐数
3.结构体整体对象的大小必须是最大对齐数的整数倍。
4.结构体内含有结构体也按该结构体的大小计算对齐数。
#include <iostream>
using namespace std;
struct A {
int a; // 4
int b; // 4
char c; // 1
}; // 12
struct B {
bool a; // 1
bool b; // 1
}; // 2
struct C {
char A; // 1
bool b; // 1
}; // 2
// 这块要注意了,是对于最大对齐数的整数倍,虽然结构体A大小是12,但是12和对齐系数相比较,对齐系数4较小,这个结构体的对齐数为4
struct D {
struct A a; // 12
int b; // 4
char c; // 1
}; // 24
struct E {
int b;
char c;
struct A a;
};
// 而且对齐系数的预编译作用范围在该命令之后,之前的数据并不影响
#pragma pack (2)
struct F {
int a;
int b;
char c;
};
// 这里也要注意,还是对齐数的问题,char是1,对齐系数是2,应该用1对齐,故还是三是1的倍数。
struct G {
char a;
char b;
char c;
};
#pragma pack (4)
// 指针变量的大小是4
// 而且这里太有趣了,内存对齐只在预编译之后进行,甚至可以放在结构体内部进行,说明结构体的内存申请不是都读取完再申请,而是按顺序执行再申请
struct H {
int *a;
#pragma pack (2)
char c;
};
#pragma pack (4)
struct I {
int *a;
int c : 64;
};
struct J {
int a : 16;
int : 100; // 用来设置空位,即前四个字节之后的16个字节为空,不使用。但是也算在结构体内存里 ceil(100 / 8)
int c;
};
int main () {
cout << sizeof (struct A) << endl;
cout << sizeof (struct B) << endl;
cout << sizeof (struct C) << endl;
cout << sizeof (struct D) << endl;
cout << sizeof (struct E) << endl;
cout << sizeof (struct F) << endl;
cout << sizeof (struct G) << endl;
cout << sizeof (struct H) << endl;
cout << sizeof (struct I) << endl;
cout << sizeof (struct J) << endl;
return 1;
}
大家同时也可以看到,在结构体中的元素里后面加冒号的情况,这代表位域。表示我让某个元素一定要占有多少位。也可以不写变量名,只写变量的位域,表示这段空间不存内容但是要空闲出来。