C++结构体字节对齐

虽然内存是以自己为单位的,但大部分计算机CPU在处理内存时,并不会直接以字节为单位。处理为了提高读取速度和减少出错几率,通常会以2字节、4字节、8字节、16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度。关于更详细的内存对齐原理,这里不做详细赘述,可以参考这篇文章内存对齐。

原文地址快捷方式 -->

有效对齐值

结构体中最大字节数成员的长度和对齐模数中较小的那个值。具体参照如下表达式

有效对齐值 = min{ 结构体重最大成员长度, 对齐模数 }

对齐模数:每个特定平台编译器都有自己默认的对齐系数(也称对齐模数),比如GCC中可默认对齐模数是4(#pragma pack(4)),用户也可以通过预编译指令#pragma pack(x)来指定对齐模数,x可以是1、2、4、8、16等来指定这一对齐模数

内存对齐规则

内部对齐(偏移量对齐):结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个值的整数倍,如有需要编译器会在成员之间加上填充字节

偏移量 offset = min { 当前成员长度, 有效对齐值 } 的整数倍

结构体第一个成员的偏移量offset为0,以后的每一个成员相对于结构体首地址的offset都是该成员大小与有效对齐值中较小的那个

外部对齐(结构体整体对齐):结构体的总大小为 有效对齐值 的整数倍,如有需要编译器会在最末一个成员之后加上填充字节

结构体的总大小 = 有效对齐值 的整数倍

实际案例

以下下案例结果统一测试方式

int main(int argc, const char * argv[]) {
    NSLog(@"%lu", sizeof(s));
    return 0;
}

案例具体分析

// 默认对齐模数:4
struct {
  //4   offset = 0,占4位 [count = 4]
  int x;  
  //1       偏移1的倍数,前4个字节(0-1-2-3)被占用,偏移1的倍数从4开始站一位 offset = 4 [count = 5]
  char y; 
} s;
// 4+1 + (3) = 8
// 默认对齐模数:4
struct {
  // 4    offset = 0,占4位 [count = 4]
  int i;   
  // 1    偏移1的倍数,前4个字节(0-1-2-3)被占用,偏移1的倍数从4开始站一位 offset = 4 [count = 5]
  char c1; 
  // 1    偏移1的倍数,前5个字节(0-1-2-3)+(4)被占用,偏移1的倍数从4开始站一位 offset = 5 [count = 6]
  char c2; 
} s;
// 4+1+1 + (2) = 8
// 默认对齐模数:4
struct {
  //1 offset = 0,占1位 [count = 1]
  char c1; 
  //4 偏移4的倍数,前1个字节(0)被占用,偏移4的倍数前边填充(1-2-3),从4开始站一位 offset = 4 [count = 8]
  int i;   
  //1 偏移1的倍数,前8个字节(0-1-2-3)+(4-5-6-7)被占用,偏移1的倍数 offset = 8 [count = 9]
  char c2; 
} s;
// 1+(3)+4+1 + (3) = 12
// 有效对齐值:4
struct {
  char c1; // 1     offset = 0,占1位 [count = 1]
  char c2; // 1     offset = 1,占1位 [count = 2]
  int i;   // 4     offset = 4,占1位 [count = 8]
} s;
// 1+ 1 + (2) + 4 = 8

参考文献

C/C++内存对齐详解

内存对齐

你可能感兴趣的:(C++结构体字节对齐)