STATUS: NOMINAL LOCAL TIME: 00:00:00 返回园内

[C++]内存对齐

[C++]内存对齐

不同类型的内存大小

数据类型 32位大小 64位大小
char 1 1
short 2 2
int 4 4
long 4 8
long long 8 8
指针 4 8
float 4 4
double 8 8

对齐规则

编译器有一个#pragma pack(n)表示默认对齐单位,实际进行结构体对齐时,会取n和成员中最长的数据类型的长度作为对齐单位,具体规则如下:

  1. 第一个成员变量的偏移量为 0。
  2. 其他成员变量的地址必须是其大小和对齐单位中较小值的整数倍。
  3. 结构体总大小必须是最大对齐单位的整数倍。
  4. 如果结构体中嵌套了其他结构体,嵌套结构体的起始地址也需要满足其最大对齐单位的整数倍。

例子

#pragma pack(4)  // 默认对齐值

struct A
{
    char x; // 占用地址0
    int y; // 偏移量必须是4的整数倍,因此占用地址4567
    char z; // 占用地址8,为了满足结构体大小为4的整数倍,地址9、10、11也算作A的内存
}; // 大小为12

struct B
{
    char x;  // 0
    int *p;  // 64位下大小为8,因此起始地址为8
    int y;   // 16
}; // 大小为24
struct C
{
    int x;  // 0
    B b;  // 这里看B的最大对齐值,为8,所以起始地址为8,占用24字节
    char c;  // 32
}; // 大小应该为8的整数倍,所以是40

类的内存对齐

class B
{
protected:
    char x;  // 0
    int *p;  // 64位下大小为8,因此起始地址为8
    int y;   // 16
public:
    B() : x('0'), p(nullptr), y(0) {}
    void Foo()
    {
        return;
    }
}; // 这个类没有虚函数,对齐方式与结构体相同,大小为24
class B
{
protected:
    char x;  // 0
    int *p;  // 64位下大小为8,因此起始地址为8
    int y;   // 16
public:
    B() : x('0'), p(nullptr), y(0) {}
    void Foo()
    {
        return;
    }
    virtual void Bar() = 0; // 加上虚函数后,起始地址存的是虚函数表
}; // 大小为32

class C
{
protected:
    char x; // 起始地址为8
public:
    virtual void Bar()
    {
        // do nothing
        return;
    }
};
// 相当于struct C {void ** vtable; char x;};
// 对齐单位是8,所以大小为16
posted @ 2026-04-26 15:53  猫爹爱猫娘  阅读(5)  评论(0)    收藏  举报