背景
C++ 中最基本的存储单位是字节,C++ 中所有的数据都是由对象组成的,每一个对象都包含了一个或多个内存位置;类对象按其成员变量的声明顺序分配内存空间;普通类的内存大小为其所有非静态成员变量内存大小之和(忽略内存对齐)。
成员顺序不同类的大小不一样
#include "iostream"
using namespace std;
class classA
{
public:
classA() = default;
~classA() = default;
private:
char x;
short y;
int z;
};
class classB
{
public:
classB() = default;
~classB() = default;
private:
char x;
int z;
short y;
};
int main()
{
cout << "classA 大小:" << sizeof(classA) << endl;
cout << "classB 大小:" << sizeof(classB) << endl;
system("pause");
return 0;
}
classA 和 classB 的区别在于其成员顺序不一样,代码运行结果如下:
内存对齐
计算机中的内存是按字节划分的,理论上任何类型的变量的方位都可以从任意位置开始,但实际上为了提高 CPU 的访问速度,各个数据类型需要按照一定的规则在内存空间上进行排列,而不是挨个的顺序排列,这就是内存对齐。
内存对齐规则
内存对齐的规则包括两部分:
①. 自然对齐:数据要根据类型存放到其数据类型大小的的整数倍的地址处。
比如 char 为 1 个字节可以放在任意地址处、int 为4个字节则必须放在 4 的倍数的地址处,
以上面两个类为例: ②. 规则对齐:在自然对齐完成后,编译器将对自然对齐产生的空隙填充无效数据,且填充后结构体占的内存空间为其最大数据类型成员大小的整数倍。
以上面两个类为例,查看内存布局:
classA 布局:
classB 布局:
打印类成员的偏移地址
把 0 强制转换为 classA 的地址,即假设 classA 地址为 0 时,然后获取其成员的地址就是该成员相对classA 的偏移量:
class classA
{
public:
classA() = default;
~classA() = default;
public:
charx;
shorty;
intz;
};
int main()
{
cout << "x 偏移地址:"<< reinterpret_cast<int>(&(static_cast<classA*>(0)->x)) << endl;
cout << "y 偏移地址:" << reinterpret_cast<int>(&(static_cast<classA*>(0)->y)) << endl;
cout << "z 偏移地址:" << reinterpret_cast<int>(&(static_cast<classA*>(0)->z)) << endl;
system("pause");
return 0;
}
代码执行如下:
pragma pack(n)
可以使用 #pragma pack(n) 来指定以 n 字节进行对齐,但当 n 大于类中最大成员数据类型时将不起作用。
通常情况下我们不需要关心字节对齐情况,有编译器默认处理即可,一般在进行网络数据传输时需要指定字节对齐。
|