C/C++中 union/struct/class的内存对齐

时间:2022-09-05 11:50:47

1.联合体

  • 在联合体中,各成员共用同一内存空间,以最大元素为准。
  • 当一个联合被说明时,编译程序自动地产生一个变量,其长度为联合中最大的变量长度。
union un
{
    char a[17];
    int b;
};

在32位机器中,上述联合体u的占用字节数为20。


2.结构体

  • 结构体的第一个数据成员放在offset为0的地方,之后所有元素的起始位置都必须是当前元素的整数倍
  • 若结构体A 中含有结构体B,则B 的起始位置也必须是B 中最大成员的整数倍
  • 结构体的大小必须是最大基本数据类型(char、int、float、double)的整数倍
union un
{
    char a[17];
    int b;
};

struct data
{
    char ch;
    short a;
    int b;
    un c;
    double d;
    float e[2];
};

int main()
{
    data da;
    cout << sizeof(un) << endl << sizeof(data) << endl;
    cout << &da<< "\t" << &da.a << "\t" << &da.b << "\t" << &da.c << "\t" << &da.d <<"\t" << &da.e << endl;
    return 0;
}

在32位机器中,上述结构体data的占用字节数为48。
运行结果为:
C/C++中 union/struct/class的内存对齐

在内存空间的分布如下:
C/C++中 union/struct/class的内存对齐

图中的红色竖线即代表data结构体中的各元素。


3.指定对齐值

编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:

  • 如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式。
  • 如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

结构的总大小也有个约束条件,分下面两种情况:

  • 如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数
  • 否则必须为n的倍数。

#pragma pack(2)
#include <iostream>
using namespace std;

union un
{
    char a[5];
    int b;
};

struct data
{
    char ch;
    int a;
    un u;
    char b;
};

int main()
{
    data da;
    cout << sizeof(un) << endl << sizeof(data) << endl;
    return 0;
}

在32位机器中,上述联合体un 和结构体data 所占的字节数分别为6,14。


4.其他

  • 在64位机器中,指针变量所占字节数分别为 8 字节。
  • 在C++中, 若一个类含有虚函数,则还要加上虚表指针所占空间。
#include <iostream>
using namespace std;

struct data
{
    char ch;
    virtual void foo() {}
};

int main()
{
    data da;
    cout  << sizeof(data) << endl;
    return 0;
}

在32位机器中,上述data 类对象所占空间为8 字节。