16. 结构体占内存大小是怎么计算的,有哪些原则?

结构体的内存大小计算主要遵循以下原则:

  1. 每个成员类型的大小:每个成员的内存大小由它的类型决定。例如,int 通常是 4 字节,char 是 1 字节,double 是 8 字节,等等。
  2. 成员的对齐要求:系统对不同数据类型有对齐要求。例如,在 32 位系统中,int 通常要求 4 字节对齐,double 通常要求 8 字节对齐。这意味着该成员的起始地址必须是其大小的整数倍。
  3. 结构体的对齐要求:结构体的总大小必须是其最大对齐成员的倍数。这通常会导致在结构体末尾添加填充字节,以确保结构体的对齐符合最大成员的对齐要求。

1. 内存对齐原则

每个成员在结构体中的位置,必须满足它自身的对齐要求。编译器可能会在成员之间添加填充字节(padding),以保证每个成员的起始地址满足其对齐要求。

  • 对齐要求是指内存地址必须是某个数值的倍数,通常是 2 的幂。
  • 最后,结构体的大小需要是最大对齐的倍数。

2. 计算步骤

  • 逐一计算每个成员的大小。
  • 考虑对齐要求,并在必要时加入填充字节。
  • 最后,确保结构体的总大小是对齐要求的倍数。

3. 示例

示例 1:简单结构体
struct S1 {
    char c;   // 1 字节
    int i;    // 4 字节
    double d; // 8 字节
};
  • char c 占 1 字节,位于结构体的开始,偏移量为 0。对齐要求为 1 字节,因此无需填充。
  • int i 占 4 字节,要求 4 字节对齐。因为上一个成员 char 只占用了 1 字节,因此在 int 前需要填充 3 字节(地址 1 到 3),i 位于地址 4 到 7。
  • double d 占 8 字节,要求 8 字节对齐。上一个成员 int 占用 4 个字节,因此 d 可以直接存储在地址 8 到 15。

总内存布局如下:

字节偏移成员占用大小
0char c1 字节
1 - 3填充3 字节
4 - 7int i4 字节
8 - 15double d8 字节
  • 总大小为 16 字节。
  • 由于 double 是对齐要求最大的成员,结构体的总大小必须是 8 的倍数,所以没有额外的填充字节。
示例 2:更复杂的结构体
struct S2 {
    char c1;  // 1 字节
    char c2;  // 1 字节
    double d; // 8 字节
    int i;    // 4 字节
};
  • char c1 占 1 字节,偏移量 0。
  • char c2 紧接着 c1,占 1 字节,偏移量 1。
  • double d 要求 8 字节对齐,但上一个成员 char c2 的地址为 1,因此必须插入 6 字节的填充,使 d 的起始地址为 8。
  • int i 要求 4 字节对齐,d 占用了 8 到 15 字节,因此 i 从 16 开始,位于 16 到 19 字节。

内存布局如下:

字节偏移成员占用大小
0char c11 字节
1char c21 字节
2 - 7填充6 字节
8 - 15double d8 字节
16 - 19int i4 字节
  • 目前为止占用了 20 字节。
  • 最大对齐单位是 double(8 字节),因此结构体的大小必须是 8 的倍数,最后需要添加 4 字节的填充,使总大小达到 24 字节。
示例 3:位域的结构体
struct S3 {
    int a : 4; // 位域,占用 4 位(0.5 字节)
    int b : 4; // 位域,占用 4 位(0.5 字节),可以与 a 共用一个字节
    int c : 8; // 位域,占用 8 位(1 字节)
    double d;  // 普通成员,占用 8 字节
};
  • ab 可以共享一个字节,存储在字节 0。
  • c 占用 1 字节,存储在字节 1。
  • double d 需要 8 字节对齐,因此需要从字节 8 开始,因此会有 6 字节的填充。

内存布局如下:

字节偏移成员占用大小
0a:4 + b:41 字节
1c:81 字节
2 - 7填充6 字节
8 - 15double d8 字节
  • 总大小为 16 字节。

4. 总结计算原则

  1. 逐一计算每个成员的大小和对齐要求
  2. 对齐补齐:如果一个成员的起始地址不满足对齐要求,则需要填充字节来对齐它。
  3. 结构体对齐:结构体的总大小应是其最大成员的对齐要求的倍数,因此需要在结构体末尾填充字节。

5. 注意点

  • 平台相关性:不同平台对不同类型的对齐要求可能不同,因此同一个结构体在不同平台上的大小可能不同。
  • 位域的实现依赖于编译器:位域的存储和对齐可能因编译器的不同而不同,位域的使用需要考虑到目标平台的实现细节。
  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dingdongkk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值