[C++系列] 15. C++结构体内存对齐规则

1. 如何计算类的大小

class A1 {
	char c;                     // char类型占1字节,从第一个字节开始存储
	int a;                      // int类型占4字节,向后偏移3个字节,从第4个字节起开始存储
	double d;                   // double类型占8字节,存满默认的8字节	                            
};                                  // VS默认对齐8,Linux默认对齐4

int main() {
	cout << sizeof(A1) << endl; // 16,为默认字节对齐数8的整数倍,即返回16
	system("pause");
	return 0;
}

class A1 {
	char c;                      // char类型占1字节,从第一个字节开始存储
	double d;                    // double类型占8字节,存满默认的8字节,两者加起来即为16
	int a;                       // int类型占4字节,总共占20字节,但不为默认字节对齐数的整数倍
                                     // 即离它最近的为24,即返回24
};

int main() {
	cout << sizeof(A1) << endl;  // 24
	system("pause");
	return 0;
}

class A1 { 

	class A2 {                   // 嵌套类 A2占8个字节
		int a;
		char c;
	};

	char c;
	double d;
	int a;
};

int main() {
	cout << sizeof(A1) << endl;  // 24,其实A2在A1中定义,注意:仅为定义所以A1不包含A2成员
	system("pause");             // 光定义不会占A1类本身的空间,若定义A2的数据成员的话字节数发生变化。
	return 0;
}

2. 结构体内存对齐规则

1)第一个成员在与结构体偏移量为0的地址处。
2)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
      注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
      VS中默认的对齐数为8,gcc中的对齐数为4
3)结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4)如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

3. 常见面试题

1)结构体怎么对齐? 为什么要进行内存对齐?

struct A {
    char c;
    int i;
}

若无内存对齐情况下,按照连续存储时,1234 5678作为8字节,在结构体中,char c会存储在1号位上,而int i会存储在2345位上,而CPU在读取在访问c的时候,每次访问4个字节,没有什么问题,会先拿出1---4,再拿出5---8,但是int i被切割开了,仍需要做字节切割及字节拼接,效率很低。

而进行内存对齐时,将char c存放在1号位,再偏移3个字节,将int i存储在5--8号位,这样CPU进行访问的时候,不必做字节上的拼接和切割,效率会大大提高。是一种典型的空间换时间以提高效率的方式。

2)如何让结构体按照指定的对齐参数进行对齐?

#pragma pack(4)   // 指定默认对齐数

3)如何知道结构体中某个成员相对于结构体起始位置的偏移量?

class A1 {
public:
	int a;
	char c;
	float f;
	
};

int main() {
	A1 a;
	float* pf = &a.f;                           // 拿到f的地址
	float* pa = (float*)&a;                     // 做强转保持同类型
	cout << (pf - pa) * sizeof(float*) << endl; // 乘以sizeof(类型字节数)获取字节偏移量
	cout << &(((A1*)0)->f) << endl;             // 特殊用法:获取成员相对起始位置的偏移量
	system("pause");
	return 0;
}


4)什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景?

大端:正常的阅读顺序,即高位存低地址。

小端:低位存低地址。

给一个int类型赋值为1,将其转为char类型,char类型仅占1个字节,若char类型结果为1的话,说明低地址存在低位,低地址存在高位为小端。反之char类型如果为0的话,为大端。

猜你喜欢

转载自blog.csdn.net/yl_puyu/article/details/88817407
今日推荐