C++内存对齐

为什么要内存对齐

方便计算机读写数据。对齐的地址一般都是 n(n = 2、4、8)的倍数。

  1. 1 个字节的变量,例如 char 类型的变量,放在任意地址的位置上;

  2. 2 个字节的变量,例如 short 类型的变量,放在 2 的整数倍的地址上;

  3. 4 个字节的变量,例如 float、int 类型的变量,放在 4 的整数倍地址上;

  4. 8 个字节的变量,例如 long long、double 类型的变量,放在 8 的整数倍地址上;

基本类型所占字节数

  1. char 1

  2. short 2

  3. int 4

  4. long 4(32位)或者8(64位)

  5. long long 8

  6. float 4

  7. double 8

  8. 指针 4(32位)或者8(64位)

  9. 枚举 4

影响内存对齐的因素

  1. 变量的排列顺序

  2. 取消变量对齐:attribute((packed))

  3. #pragma pack (n):让变量强制按照 n 的倍数进行对齐

内存对齐原则

  1. sizeof一个结struct、class的结果必然是其内部的“最宽基本类型成员”的整数倍。

    struct A { int a; char b; }; //sizeof(A)的结果是4的倍数。

    struct B { int a; char b; double c; }; //sizeof(B)的结果是8的倍数。

    struct C { A a; char b; }; //sizeof(C)的结果是4的倍数。

    struct D { B a; char b; }; //sizeof(D)的结果是8的倍数。

结构体或类的自身对齐值:其成员中自身对齐值最大的那个值。

#include <cstdlib>
#include <cstdio>

class A {
public:
    int m_a;//占0~3字节
    char m_b;//占第4字节
    char m_c;//占第5字节,第6~7字节空着
};

class B {
public:
    char m_a;//占第0字节,1~3空着
    int m_b;//占4~7字节
    char m_c;//占第8字节,第9~11空着
};

class C {
public:
    char m_a;//占第0字节
    char m_b;//占第1字节,2~3空着
    int m_c;//占4~7字节
};

int main()
{
    printf("%d\n%d\n%d\n", sizeof(A), sizeof(B),sizeof(C));//8 12 8
    system("pause");
    return 0;
}

虚函数表也遵循字节对齐

虚函数表指针永远在类的开头位置,并且虚函数表指针占用4(32位)或8(64位)字节。

#include <cstdlib>
#include <cstdio>

class D {
public:
    virtual void f() {}
};

class E {
public:
    virtual void f() {}
    double m_a;
};

class F {
public:
    virtual void f() {}
    int m_a;
};

class G {
public:
    virtual void f() {}
    char m_a;
};

int main()
{
    //结果4 16 8 8
    printf("%d\n%d\n%d\n%d\n", sizeof(D), sizeof(E), sizeof(F), sizeof(G));
    system("pause");
    return 0;
}

参考文章

https://blog.csdn.net/weixin_48896613/article/details/127371045