struct 的内存对齐

成员对齐大小概念

成员对齐值

struct类型中, 每个成员相对于整个 struct 类型变量的开始地址而言, 它的偏移量必须是 对齐值的整数倍.
struct 成员对齐值 由两个规则影响:

  • [[# 成员默认对齐值]]
  • [[# pragma pack(n) 的作用|pragma pack(n)]]
    成员最终对齐值min(成员默认对齐值, n)
推论: 成员对齐大小 总是2的幂次

证明: 
- 由于内置类型成员对齐大小都是2的幂次, 并且 `pragma pack (n)` 只能设为2的幂次
- 由于嵌套结构体成员对齐大小 由它内部成员决定 (也是2的幂次), 或由 alignas 控制 (也是2的幂次)
- 因此成员对齐值 总是2的幂次
成员默认对齐值
  • 内置类型的默认对齐值: 比如 int 对齐值为 4, double 为 8 , char 为1字节
  • 数组类型的默认对齐值: 数组的对齐值 = 数组元素类型的默认对齐值。
  • struct 类型的默认对齐值: 参见 [[# struct 对象作为成员时的内存对齐值]]
    • 结构体的默认对齐值 = 它所有成员中最大的默认对齐值
    • 若由 alignas 指定, 则为指定值.
#pragma pack(n) 的作用
  • n 只能设定为 2 的幂次
  • 一般用于减小对齐值, 使内存布局更紧凑.
  • 它将修改 struct 类型 中 成员的对齐值, 使得其成员对齐值变为 min(成员默认对齐值, n)

struct 整体的内存大小

struct 对象作为成员时的内存对齐值

当结构体 a 作为 另一个结构体的 数据成员时, 需要考虑 成员 a 的对齐值

  • struct 内存对齐值 影响该成员的起始地址和内存大小
    • struct 成员的起始地址 必须是 struct 内存对齐值 的整数倍
    • struct 内存占用大小 必须是 struct 内存对齐值 的整数倍
  • struct 内存对齐值 由以下事物决定
    • alignas 直接指定
    • 否则为所有[[#成员对齐值]]的最大值
***推论:*** 
- struct 对象的内存对齐值 是[[#成员对齐值]]的整数倍
	- 若没有指定 `#pragma pack(n)`, 则内存大小是所有[[#成员默认对齐值]] 中最大值 的整数倍
	- 如果指定了 `#pragma pack(n)`, 则内存大小必然是 `n` 的整数倍
- 若指定了 `alignas(m)` ,则内存大小必然是 `m` 的整数倍
- 以上两条规则独立地起作用
alignas 规则

作用:

  • 用于控制结构体整体的对齐为 m, 它不修饰每个成员的对齐规则.
  • 设置 alignas(m) 后, 结构体的起始地址总大小必须对齐到 m

取值规则:

  • 取值 m 只能是2的幂次
  • 取值 m 不能小于 最大的[[#成员对齐值]], 且必须是所有成员对齐值的整数倍
    • 若没有指定 #pragma pack(n), 则 m 不能小于 最大的[[#成员默认对齐值]]
    • 若指定了 #pragma pack(n), 则 m 不能小于 n

struct 内存对齐总结和例子

总结

从下面例子中的内存布局图来看

  • 结构体内存总是要占据一个完整矩形
  • #alignas(n) 实际上控制了 这个矩形列的大小
  • #pragma pack(n) 则控制成员之间的紧密程度

例子

例子1:

struct A {    //结构体对齐值 8
	double x;   // 成员对齐值 8 , offset = 0
	int a;      // 成员对齐值 4 , offset = 8
	char b[1];  // 成员对齐值 1 , offset = 12
	int c;      // 成员对齐值 4 , offset = 16
};

解释:

  • 由于不指定 pack (n), 所有成员的对齐值都是 成员默认对齐值
  • 结构体的整体对齐值为 8
  • 总结构体大小为24, 内存布局如图

例子2:

struct D { //结构体对齐值 4, 总大小8
	int a; // 成员对齐值 4
	int b; // 成员对齐值 4
};

struct B { //结构体对齐值 4, 总大小24
	D d;   //成员对齐值 4 , 大小为 8
	int a; //成员对齐值 4
	char b[10]; //成员对齐值 1
};

解释:

  • 成员 d 的默认对齐值为 它的成员最大对齐值, 因此为4
  • 整体的 B 的对齐值为4,
  • 内存布局如图

例子4

#pragma pack(2)
struct alignas(4) A {      // 整体对齐值 4, 总大小 40
	double x;               // 成员对齐值 2, offset 0
	double y;              // 成员对齐值 2,	offset 8
	int a;                  // 成员对齐值 2, offset 16
	char b1[7];            // 成员对齐值 1, offset 20
	char b2[7];             // 成员对齐值 1, offset 27
	int c;                 // 成员对齐值2, offset 34
}; 

解释:

  • 成员对齐值= min (2, 成员默认对齐值)
  • 结构体总大小为4的倍数
  • 最后一个成员结束为34+4=38字节, 但考虑总大小为4的倍数, 因此是40字节
  • 布局如下

例子5

struct alignas(64) A {  // 整体对齐 64字节 总大小64字节
	double x; 
	int a;
	char b1;
	char b2;
	int c;
};

内存布局如图

posted @ 2025-04-15 22:37  Ace233  阅读(28)  评论(0)    收藏  举报