结构体的内存分配
举个例子就明白了,如下图,似乎除了结构体名没什么区别,内存大小和内存分布也应该没什么区别,
但是实际上:
sizeof(A) = 9
sizeof(B) = 16
导致这一差异的就是内存对齐,为什么有内存对齐,以及什么是内存对齐在这就不阐述了,可以自行度娘,反正目的是为了加快性能, 内存对齐的规则如下,也是编译器给结构体开辟内存时遵循的规则:
1、第一个成员的相对于结构体首地址的偏移(offset)为0.
2、每个成员的相对于首地址的偏移(offset)为:
对齐值与成员类型长度的较小值
的整数倍
3、没有指定对齐值的情况下,默认对齐值为结构体成员类型最长的值作为对齐值
4、结构体的总大小,为对齐值的整数倍。
这个规则就确认了结构体成员的内存分布及内存大小,上图中,结构体A指定了内存对齐为1字节对齐,那么按照规则A中各成员分布如下图:
B为默认对齐,显然,对齐值为类型int的长度,假设为4,内存分配如下图:
为什么会如此分布?我们尝试给每个成员分配内存
- c1: 分配内存为1字节,占据索引为“0”的位置
- i: 分配4个字节长度,但是按照规则2,距首地址要有4的整数倍偏移,所以i为起始位置为“4”,长度为4
- c2: 分配1字节,占据索引为“8”的位置 s2: 分配2字节,依照规则2,偏移为2个倍数,起始为“10”,长度为2
- c3:分配1个字节,占据索引为“12”的位置,按照规则4,总长度需要是4的倍数,因此还需要额外补充3个字节
因此B的总长度16,其中有部分内存是未使用的,可以说是浪费的,但是合理的
以下是一段测试验证代码:
#include <iostream>
#include <new>
#include <cstdio>
using namespace std;
#pragma pack(1)
struct A
{
public:
char c1;
int i;
char c2;
short s1;
char c3;
};
#pragma pack()
struct B
{
char c1;
int i;
char c2;
short s1;
char c3;
};
void printA(A a){
cout<<"A:"<<a.c1<<","<<a.i<<","<<a.c2<<","<<a.s1<<","<<a.c2<<","<<a.c3<<endl;
int h1 = 0x000000ff & a.i;
int h2 = 0x000000ff & (a.i >>8);
int h3 = 0x000000ff & (a.i >>16);
int h4 = 0x000000ff & (a.i >>24);
cout<<"h1:"<<h1<<" h2:"<<h2<<" h3:"<<h3<<" h4:"<<h4<<endl;
}
void printB(B a){
cout<<"B:"<<a.c1<<","<<a.i<<","<<a.c2<<","<<a.s1<<","<<a.c2<<","<<a.c3<<endl;
int h1 = 0x000000ff & a.i;
int h2 = 0x000000ff & (a.i >>8);
int h3 = 0x000000ff & (a.i >>16);
int h4 = 0x000000ff & (a.i >>24);
cout<<"h1:"<<h1<<" h2:"<<h2<<" h3:"<<h3<<" h4:"<<h4<<endl;
}
int main(int argc, char *argv[])
{
cout<<"sizeof(A)"<<sizeof(A)<<endl;
cout<<"sizeof(B)"<<sizeof(B)<<endl;
//26个字母的字符
char buff[26] = {0};
for(int i=0;i<26;i++)
buff[i] = 97+i;//字符 a 的值为97
A a = {0};
memcpy(&a,buff,sizeof(A));
printA(a);
B b = {0};
memcpy(&b,buff,sizeof(B));
printB(b);
}
程序打印
打印结果和理论上是一致的(下图的内存分布)
假设结构体重包含结构体内存怎么分配?依然按照原则分配就是,值得一提的是,内存对齐值不是结构体的长度,而是结构体内部成员类型长度最大的值,你可以理解为对齐值对比的是基础类型的内存长度(char,short,int,long,double,float等),下图中内存对齐值不是sizeof(B),而是结构体B中的类型int的所占内存的长度值。
那么这里的B的起始位置为什么在“105”而不是在“102”?
依然对比规则,规则2规定了,每个成员的偏移量为内存对齐值的整数倍,结构体B才是是D的成员,所以B的起始位置距离D结构体的起始位置要是4的倍数,因此B的起始位置在“105”