1.为什么要实现内存对齐
因为在内存中我们一般读取数据不是一个一个内存来读取,一般都是分为一个个内存块来读取。
例如:
a占一个字节 ,b占四个字节
因为在内存中我们一般读取数据不是一个一个内存来读取,一般都是分为一个个内存块来读取。如果我们要读取b这个数据就需要像下面这样将b分为两段然后再进行剪切拼接,将b的前三个字节和第二段的b的第四个字节都剪切下来再进行拼接,这样会耗损大量的时间。
而如果有内存对齐的话就不会出现这种问题
a占一个字节给它后面再分配三个字节
b占四个字节
然后每次读取四个字节的话,不用进行复杂的分割拼接,大大的提高了效率。
1.因为内存对齐可以节省程序运行时间,提高效率。
而且有的cpu因为硬件问题 ,只能在固定位置读取数据,必须进行内存对 齐,否则就会出错。
简而言之就是牺牲内存换时间。
2.结构体怎末对齐
- 第一个成员在与结构体偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8 - 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是
所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
3. 举例说明
class A {
int a;//4
int b;//4
char c;//1
double d;//8
};
void test() {
cout << sizeof(A) << endl;
}
int main() {
test();
return 0;
}
这个类中 a为整型占四个字节,b也为整型也是四个字节,c为字符型占一个字节但是后面d为浮点数所以要向后偏移七个字节,d为浮点数占八个字节。
所以程序运行完后为4+4+8+8=24个字节。
//
//
//
class B {
char a;//1
double b;//8
int c;//4
};
a为字符型占一个位置 但是后面b为浮点数所以需要给a再分配七个字节,b为浮点数,所以站八个字节,c为整形所以占四个字节。
8+8+4=20
但是因为结构体总大小为最大对齐数的整数倍,所以必须再加四个字节,从而20+4=24为最大对齐数8的整数倍,所以这个结构体的大小等于24.
嵌套结构体内存对齐
class A {
int a;//4
int b;//4
char c;//1
double d;//8
};
class C {
char a;//1
int b;//4
int c;//4
A objA;//24
};
void test() {
cout << sizeof(A) << endl;
cout << sizeof(C) << endl;
}
a为字符类型占一个字节但是b为整型占四个字节所以需要给a补三个字节,b为整形占四个字节,c为整型占四个字节,a大小加b大小+c大小为4+4+4=12
但是因为所有最大对齐数(含嵌套结构体的对齐数)为8
所以应该补四个字节12+4=16
上面A的大小为24 上面已经举例说明过,
最终C的大小为24+16=40
4.如何让结构体按照指定的对齐参数进行对齐
只需要输入#pragma pack(想要指定的对齐参数)
5.如何知道结构体中某个成员相对于结构体起始位置的偏移量
想要求结构体中某个成员相对于结构体起始位置的偏移量最简单的方法就是取地址相减
代码如下
struct C {
char a;//1
int b;//4
int c;//4
A objA;//24
};
void test() {
C a;
cout <<(char*) &a.b - (char*)&a << endl;
}
int main() {
test();
return 0;
}
运行结果如下
如果大家觉得我有说得不对的话,欢迎大家批评指导😊