空结构体所占内存为1 用来区分结构体
#pragma pack(n)指定按照n对齐
vs默认用8对齐
计算方式:(表面理解)
1.先找出最大的类型变量
2.在它之前的总内存必须和最大类型对齐(整数倍)
3.在它之后的总内存必须和最大类型对齐(整数倍)
深度理解:
1.每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐
2.确定的对齐参数必须能够整除起始地址(或偏移量)
3.偏移地址和成员占用大小均需对齐
4.结构体成员的对齐参数为其所有成员使用的对齐参数的最大值
5.结构体总长度必须为所有对齐参数的整数倍
代码实现:
struct person
{
int a;
char c;
double d;
char e;
};
int main()
{
struct person p;
cout << "p所占的内存:" <<sizeof(p) << endl;
}
struct person
{
int a;
int b;
double d;
};
int main()
{
struct person p;
cout << "p所占的内存:" <<sizeof(p) << endl;
}
当含有数组时:把数组拆分计算
struct person
{
int b[5];
double d;
};
int main()
{
struct person p;
cout << "p所占的内存:" <<sizeof(p) << endl;
}
#pragma pack(n)的使用n(1,2,4,8,16)
(当n大于最大数据类型字节时失效,取两者的小值)
- 先找到最大类型位置
- 前半部分内存和为n的倍数
- 后半部分也要为n的倍数
未设置#pragma pack(n) 结果为:24
struct person
{
char c;
double b;
int a;
};
设置#pragma pack(16) 结果为:24 当n>最大数据类型时 取数据类型的值
#pragma pack(16)
struct person
{
char c;
double b;
int a;
};
设置#pragma pack(4) 结果为:16 当n<最大数据类型时 取n
#pragma pack(4)
struct person
{
char c;
double b;
int a;
};
设置#pragma pack(2) 结果为:14
#pragma pack(2)
struct person
{
char c;
double b;
int a;
};
设置#pragma pack(1) 结果为:13
#pragma pack(1)
struct person
{
char c;
double b;
int a;
};
复杂的结构体内存计算:
32位下:
struct person
{
enum per
{
A,B,C,D,E
}G; //枚举要定义
int a[10];
char c;
double b;
int *p;
union H
{
int n;
double l;
}Y; //结构体也要定义
};
person *p;
cout << sizeof(p) << endl;//指针占4个字节(32位) 64位的话是 8个字节
cout << sizeof(*p) << endl; //结果位 72个字节
cout << sizeof(p->a) << endl;// 占40个字节
cout << sizeof(p->b) << endl;// 占8个字节
cout << sizeof(p->c) << endl;// 占1个字节
cout << sizeof(p->d) << endl;// 指针占4个字节(32位)
cout << sizeof(p->G) << endl;// 占4个字节(枚举类型)
cout << sizeof(p->Y) << endl;// 占8个字节(联合体取最大内存)
计算图解:
注意事项:未定义的 枚举类型和联合体不占用内存
struct person
{
enum per
{
A, B, C, D, E
};
union H
{
int n;
double l;
};
};
person p;
cout << sizeof(p) << endl;//指针占1个字节空结构体占用一个字节,来区分结构体
在这里补充一个问题:(感谢评论区提出的问题)
注意内存分配的问题:
struct MyStruct
{
int b;
char c;
short d;
short e;
char f;
short g;
}a1;
void main()
{
cout << sizeof(a1) << endl;
}
如果按照正常的计算方法:
int 为最大类型 对齐字节为 4
所以 cdefg相加的结果为 1+2+2+1+2=8 刚好为4的倍数,所以结果为12 但结果为16
这里需要注意一个细节,就是跨越对齐字节问题,
(当一个数据跨越了两个对齐字节时,当存放不下时需要额外的分配一个对齐字节,不得跨越对齐字节)
struct MyStruct
{
int b;
char c;
short d;
short e;
}a1;
void main()
{
printf("%p\n", &a1.b);//获取地址
printf("%p\n", &a1.c);
printf("%p\n", &a1.d);
printf("%p\n", &a1.e);
cout << sizeof(a1) << endl;
}
这里结果为12 ,它的内存分配解释如下:
一般会以为:c+d+e=5,然后在5后面补充3个字节
实际上:由于c+d=3 4-3=1 1个字节存放不了 e(2个字节),所以补充一个字节,
然后开辟新的4个字节 存放 e+2(两个补充字节)
图解为:
返回到之前的问题:结果为什么为16
计算方式为:(红字为填充)
4 + (1+2+1) +(2+1+1)+(2+2)=16
图解为:
再例如:
struct MyStruct
{
char a;
int b;
int c;
double d;
}a1;
void main()
{
printf("%p\n", &a1.a);
printf("%p\n", &a1.b);
printf("%p\n", &a1.c);
printf("%p\n", &a1.d);
cout << sizeof(a1) << endl;
}
还有补充有多个最大数据类型时的计算:
计算方法为:把最大类型变量当作节点,节点左右两边的类型字节对齐。
struct MQ
{
char a;
int b;
char c;
short d;
short e;
char f;
short g;
int h;
char k;
};
void main()
{
cout << sizeof(MQ) << endl;
}
计算过程为: