字节对齐

65 阅读3分钟

默认对齐规则

  • 成员对齐:每个变量类型的起始地址必须是其自身大小(或编译器/平台定义的对齐值)的整数倍。
  • 结构体整体对齐:结构体总大小必须是其成员中最大对齐值的整数倍。
char: 1 字节
short: 2 字节
int/float: 4 字节
double/指针(x86): 4 字节
double/指针(x64): 8 字节

struct Example1 {
    char a;     // 1 字节,对齐到 0
    int b;      // 4 字节,对齐到 4(起始地址必须是4的整数倍,所以要跳过 3 字节填充)
    double c;   // 8 字节,对齐到 8
};
结构体最大对齐值是8
内存布局:| a (0) | 填充3字节(1-3) | b (4-7) 必须是自身大小(4)的整数倍| c (8-15) |
总大小:16 字节(满足 double8 字节对齐)

强制 4 字节对齐的方法

(1) 使用 #pragma pack (编译器指令)(不推荐,可能失效)
#pragma pack(push, 4)  // 压入当前对齐设置,强制后续结构体按 4 字节对齐
struct MyStruct {
    char a;     // 1 字节,对齐到任意地址
    int b;      // 4 字节,对齐到 4 的倍数地址
    double c;   // 8 字节,但受 pack(4) 限制,对齐到 4 的倍数地址
};
#pragma pack(pop)      // 恢复之前的对齐设置

总大小计算

| a (0) | 填充 (1-3) | b (4-7) | c (8-15) | 总大小 = 16 字节
(2) 使用 ****alignas (C++11 标准)
struct alignas(4) MyStruct {
    char a;
    int b;
    double c;  // 若系统默认对齐为 8,此处仍会按 4 对齐
};
  • 验证对齐
static_assert(alignof(MyStruct) == 4, "Alignment error");

对齐效果验证

查看结构体大小和对齐值
struct MyStruct {
    char a;//1 字节,对齐到任意地址
    unsigned short b;//2 字节,对齐到 2 的倍数地址
    char c[5];//1 字节,对齐到任意地址
};

int main(
    int argc, char *argv[])
{
    QApplication a(argc, argv);
    qDebug()<<"size:"<<sizeof(MyStruct);
    qDebug() << "Alignment: " << alignof(MyStruct);//多少字节对齐,由结构体成员中最大值的整数倍决定
    qDebug() << "Offset of b: " << offsetof(MyStruct, b);
    qDebug() << "Offset of c: " << offsetof(MyStruct, c);//地址偏移
    return a.exec();
}
结果:
size: 10
Alignment:  2
Offset of b:  2
Offset of c:  4
成员布局:a(偏移:0), 填充1字节(偏移:1), b(偏移:2-3),c(偏移:4-8),填充1字节(9),总大小10字节
强制4字节对齐

#pragma pack(push, 4) //压入当前对齐设置,强制后续结构体按 4 字节对齐,这种方法在QTcreator msvc编译失效,仍然是2字节对齐
struct  alignas(4) MyStruct {
    char a;//1 字节,对齐到任意地址
    unsigned short b;//2 字节,对齐到 2 的倍数地址
    char c[5];//1 字节,对齐到任意地址
};
#pragma pack(pop)      // 恢复之前的对齐设置


int main(
    int argc, char *argv[])
{
    QApplication a(argc, argv);
    qDebug()<<"size:"<<sizeof(MyStruct);
    qDebug() << "Alignment: " << alignof(MyStruct);
    qDebug() << "Offset of b: " << offsetof(MyStruct, b);
    qDebug() << "Offset of c: " << offsetof(MyStruct, c);
    return a.exec();
}

结果:
size: 12
Alignment:  4
Offset of b:  2
Offset of c:  4
成员布局:a(偏移:0), 填充1字节(偏移:1), b(偏移:2-3),c(偏移:4-8),填充3字节(9-11),总大小12字节