一:系统默认方式对齐
结构体的大小是结构体成员中占用字节最大的类型的整数倍。
#ifdef __cplusplus
#define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
#else
#define offsetof(s,m) ((size_t)&(((s*)0)->m))
#endif
#define OUT(ST,VAR) cout<<#ST"."+string(typeid(ST().VAR).name())+" offsetof:"<<offsetof(ST,VAR)<<endl
#define SIZE(ST) cout << "sizeof("#ST"):" << sizeof(ST) << endl
/*
OUT(A, ch);
OUT(A, sh);
OUT(A, it);
OUT(A, d);
SIZE(A);
*/
struct A
{
char ch;
short sh;
int it;
double d;
};
A.char offsetof:0
A.short offsetof:2
A.int offsetof:4
A.double offsetof:8
sizeof(A):16
// char占两个字节,char与short之间有一个字节空闲
struct B
{
double d;
int it;
short sh;
char ch;
};
B.double offsetof:0
B.int offsetof:8
B.short offsetof:12
B.char offsetof:14
sizeof(B):16
// char占一个字节,最后一个字节空闲,但是保证了前面的成员变量的内存连续性
// 建议写法,内存占用大的放在前面;在C++类声明成员变量也是一样的
struct C
{
char ch;
short sh;
double d;
int it;
};
C.char offsetof:0
C.short offsetof:2
C.double offsetof:8
C.int offsetof:16
sizeof(C):24
// char占用2个字节,short占用6个字节;char与short之间有1个字节空闲,short与double
//之间4个字节空间,内存最后4个字节也是空闲。这种方式非常浪费内存,内存利用率低
struct D
{
int it;
double d;
char ch;
short sh;
};
D.int offsetof:0
D.double offsetof:8
D.char offsetof:16
D.short offsetof:18
sizeof(D):24
// int占用8个字节,char占用2个字节。int与double之间有4个字节空闲,char与short之间有1个字节空闲,
//内存最后有4个字节空闲,内存利用率低
struct E
{
struct F
{
int ia;
char ca;
}ff;
char ch;
};
E.ff.int offsetof:0
E.ff.char offsetof:4
sizeof(E.ff):8
E.ff offsetof:0
E.char offsetof:8
sizeof(E):12
struct G
{
char ch;
struct F
{
int ia;
char ca;
}ff;
};
G.char offsetof:0
G.ff offsetof:4
sizeof(G):12
// 结构体成员变量是结构体类型的,需要将内部结构体拆解出单个的成员再考虑整体的内存分布
结构体成员的偏移量满足:当前某个成员偏移量 % sizeof(下一个成员类型)==0
二:#pragma pack(int)指定
#pragma pack(2)
最小字节分配为2。
sizeof(A):16
sizeof(B):16
sizeof(C):16
sizeof(D):16
sizeof(E):8
sizeof(G):8