C语言结构体类型中字节补齐规则

  • 本文主要记述C语言中结构体类型字节占用的问题以及字节补齐的规则

一、结构体类型

C语言中的结构体struct是一种用户自定义的数据类型,用于将不同类型的数据组合在一起。对于处理相关联的不同数据类型的数据项(例如人的姓名、年龄、住址等信息)非常有用。

二、结构体类型的大小

  • 问题来了:结构体内部可以定义不同数据类型的变量,例如
typedef struct {
    char name[10];
    int age;
}Person;

这里定义了一个类型名为Person的结构体,内部定义了一个字符数组用来存储姓名和一个int类型变量用来存储年龄,那么它的大小应该如何计算呢?

  • char name[10] 的大小为 sizeof(char)*10 = 1*10 = 10字节
  • int age的大小为 sizeof(int) = 4字节
    难道只是简单的将两者的大小相加10+4就可以了吗?我们来验证一下
Person zhangsan;   //创建一个结构体变量
printf("张三占用的字节数:%zu", sizeof(zhangsan)); //打印它的大小

在这里插入图片描述
我们可以看到变量张三的大小并不是14而是16,这是为什么呢?

事实上,C语言对于结构体的大小有一套字节对齐规则,有时候并不是简单地将各部分变量大小相加就可以的

1、内存对齐与结构体对齐

(1)内存对齐

内存对齐是指将数据放置在特定的内存地址上,使得CPU能够高效地访问数据。现代计算机系统往往要求数据按照特定的字节边界进行对齐,以提高内存访问速度。例如,32位操作系统中的int类型通常要求以4字节对齐,即地址必须是4的倍数。

(2)结构体对齐

结构体对齐是指结构体内部的成员按照一定的规则排列和对齐,以满足内存对齐的要求。编译器会在结构体之间结构体尾部添加填充字节(padding),以保证每个成员满足内存对齐要求。

2、对齐规则

  • 每个成员的地址必须是该成员大小的整数倍。

      例如:
      4字节的int类型的地址必须是4的倍数
    
  • 编译器会在需要时插入填充字节,以保证每个成员满足内存对齐要求

  • 整个结构体的大小必须是结构体中最大的那个成员的大小的整数倍。编译器会在结构体最后插入填充字节,以保证满足对齐要求。

根据对齐要求,我们可以分析出前文中Person类型的大小为什么是16而不是14

  • 假设初始地址为0x00
-------------------------------------------------------------------------
|char|char|char|char|char|char|char|char|char|char|xxxx|xxxx|int-----int|
-------------------------------------------------------------------------
 0x00|0x01|0x02|0x03|0x04|0x05|0x06|0x07|0x08|0x09|0x10|0x11|0x12...
  • char name[10] 为十个字符类型的变量,每一个数组成员占一个字节
  • 当字符数组存储完时,下一个地址为0x10,而int型变量大小为4字节,不满足对齐规则,所以会插入两个填充字节,然后开始存储int age
  • 最终结构体大小为10+2+4=16字节,是最大数据类型int的整数倍,满足对齐规则,所以尾部不需要填充字节

另一个示例

struct Example2 {
    char a;      // 1字节
    double b;    // 8字节
    char c;      // 1字节
    int d;       // 4字节
};
  • 假设初始地址为0x00
-------------------------------------------------------------------------
|char|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|double|char|xxxx|xxxx|xxxx|int |
-------------------------------------------------------------------------
|0x00|0x01|0x02|0x03|0x04|0x05|0x06|0x07|0x08..|0x16|0x17|0x18|0x19|0x20|
  • char a位于0x00,占1字节
  • 由于下一个是double b,大小为8字节,所以需要填充7个字节,以满足对齐条件
  • char c位于0x10,占1字节
  • 下一个为int d,大小为4字节,所以要填充3个字节,以满足对齐条件
  • 最后计算大小:1 + 7 + 8 + 1 + 3 + 4 = 24,是最大的数据类型double的整数倍,满足对齐条件,不需要进行填充

3、自定义对齐

在C语言中,你还可以使用#pragma pack(2^n)这个预编译指令来更改结构体的对齐方式。

  • 例如
#pragma pack(1)
typedef struct
{
    char name[10];
    int age;
} Person;

int main()
{
    Person zhangsan;
    printf("张三占用的字节数:%zu", sizeof(zhangsan));
    return 0;
}

这里我使用指令将字节对齐大小改为1字节,意味着任何变量的存储地址和结构体的大小只要为1的倍数就可以

最终运行结果为
在这里插入图片描述

  • 注意:此方法虽然可以减少结构体的内存占用,但可能会影响CPU的访问速度,需要谨慎使用

三、总结

记录此知识点以加深理解,供日后复习使用

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值