struct用来声明一个结构体。如:
struct MyStruct {
int a;
char* p;
double b;
};
那么MyStruct占用多大内存呢?换言之,sizeof(MyStruct)会输出什么?
解答这个问题,需要从struct类型的内存占用方式来入手。首先要了解一下编译器的补齐原理。编译器为了提高访问效率,一般会按照以下规则:
- 各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。
- 结构体的整体内存占用应当是其中最大成员变量的整数倍。
如何理解这两句话呢?我们直接来看一些例子(内存占用直接写在注释里了):
例子一:
struct s1 {
double d;//0~7
int i;//8~11
char c;//12,补齐到15
};//size=16
虽然实际只占用了12个字节,但是根据规则2,补齐到最大类型(double)的整数倍,也就是16字节。
我们来换一下变量声明的顺序:
例子二:
struct s1 {
char c;//0~1
double d;//7~15
int i;//16~19
};//size=24
根据规则1,double类型d的初始位置应该是其整数倍,因此是7。再根据规则2,整个struct应当补齐知double的整数倍,也就是24字节。
来看看有数组的情况:
例子三:
struct s1 {
char c;//0~1
double d[2];//d[0]:7~15,d[1]16~23
int i;//24~27
};//size=32
double类型数组d[2]的size是16,因此综合规则1和规则2,改struct的内存为32字节。
例子四:
struct s1 {
char c; //0~1
double d[];//未指定数组大小,不实际真用内存
int i; //4~7
char c2;//8~9
};//size=16
例子中的d是个未指定大小的数组,因此并不实际占用内存。计算其余的内存应该是12。但是该struct中最大的类型确实double,因此还是要补齐到double的整数倍,也就是16个字节。
例子五:
想想另一种情况,如果没有那个double d[],那么内存占用情况将不一样,因为不用补齐到double的整数倍,而是补齐到int的整数倍,也就是12。
struct s1 {
char c; //0~1
int i; //4~7
char c2;//8~9
};//size=12