内存对齐
- 每个特定平台上的编译器都有自己的默认对齐系数(也叫对齐模数)gcc中默认#pragma pack(4),可以通过预编译命令#pragma pack(n),n = 1,2,4,8,16来改变这一系数
- 有效对其值:是给定值#pragma pack(n)和结构体中最长数据类型长度中最大的那个。有效对齐值也叫对齐单位
- 类或结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个的整数倍,如有需要编译器会在成员之间加上填充字节
- 类或结构体的总大小为有效对齐值的整数倍,如有需要编译器会在最末一个成员之后加上填充字节
- 因为内存对齐,类的大小和创建的成员属性类型强相关
内存对齐结构图
- 此为对齐系数4下的结构(32位一般情况下默认为4,64位为8),八位内存结构仿此,指针仿此
- 内存对齐和创建成员属性时的顺序有关
- 考虑如下代码:
template <class T1, class T2, class T3>
class Memory
{
public:
T1 m_v;
T2 m_v2;
T3 m_v3;
};
void test01()
{
Memory<int, char, char> me1;
Memory<int*, char, char> me1p;
Memory<char, int, char> me2;
Memory<char, int*, char> me2p;
Memory<char, char, int> me3;
Memory<char, char, int*> me3p;
cout << "int char char size: " << sizeof(me1) << endl;
cout << "int* char char size: " << sizeof(me1p) << endl;
cout << "char int char size: " << sizeof(me2) << endl;
cout << "char int* char size: " << sizeof(me2p) << endl;
cout << "char char int size: " << sizeof(me3) << endl;
cout << "char char int* size: " << sizeof(me3p) << endl;
cout << "int* size: " << sizeof(int *) << endl;
}
output:#pragma pack(8) 64位下为默认
int char char size: 8
int* char char size: 16
char int char size: 12
char int* char size: 24
char char int size: 8
char char int* size: 16
int* size: 8
output:#pragma pack(4)
int char char size: 8
int* char char size: 12
char int char size: 12
char int* char size: 16
char char int size: 8
char char int* size: 12
int* size: 8
虚继承情况下内存对齐
#纯虚函数和抽象类
- 继承情况下,会继承父类的虚函数表指针,在子类重写父类虚函数后,虚函数表指针会指向子类重写的虚函数。指针占8个字节,也参与内存对齐
- 内存对齐规则和上方一致
class MyClass
{
public:
virtual void func() = 0;
int num1;
double num2;
};
class Son :public MyClass
{
public:
void func()
{
cout << "OK!" << endl;
}
int val;
double val2;
};
void test02()
{
Son s1;
cout << "Son size: " << sizeof(s1) << endl;
test0 t1;
cout << "Myclass size: " << sizeof(MyClass) << endl;
cout << "void* size: "<< sizeof(void*) << endl;
}
output:
Son size: 40
Myclass size: 24
void* size: 8