计算结构体大小:内存对齐详解

简介: 计算结构体大小:内存对齐详解

一.什么是内存对齐

在解决这个问题之前,我们先看一组代码,大家可以思考思考会输出什么:

//结构体1
struct S1
{
  char c1;
  int i;
  char c2;
};
//结构体2
struct S2
{
  char c1;
  char c2;
  int i;
};
printf("%zd\n", sizeof(struct S1));
printf("%zd\n", sizeof(struct S2));

 我们可以看到俩个结构体的成员类型都是一模一样的,唯独不同的是成员直接的相互顺序不同,按道理来说应该输出的是同一个值,那结果真是这样吗,我们继续往下走

输出结果:

   结果非常的出人意料啊,他们的字节大小居然不一样,造成这样现象的原因就是因为存在结构体内存对齐的情况,接下来我们就来探索一下什么是结构体内存对齐以及如何计算它

二.怎么对齐的

使用 offsetof 宏来观察

什么是 offsetof 宏,我们打开 cplusplus 官网:

offsetof - C++ Reference (cplusplus.com)

       通过查询资料得知,offsetof 是用来计算结构体中成员单位相较于起始位置的偏移量的一个宏,具体使用如下

结构体S1

  //查看S1的成员的偏移量
    printf("%zd\n", offsetof(struct S1, c1));
  printf("%zd\n", offsetof(struct S1, i));
  printf("%zd\n", offsetof(struct S1, c2));

输出结果如下:

那我们就根据图示画出内存中的大概模型

结构体S2

同样的对结构体 S2 也做这样的处理

  printf("%zd\n", offsetof(struct S2, c1));
  printf("%zd\n", offsetof(struct S2, c2));
  printf("%zd\n", offsetof(struct S2, i));

输出结果:

根据图示画出内存中的大概模型

我们将俩个模型进行比较,并且结合输出观察

我们会发现

  • 在结构体 S1 中浪费了很多空间,在char c1 后浪费了 3 个字节的空间,在char c2 后浪费了 3 个字节的空间
  • 在结构体 S2 中,char c1 后并没有浪费空间,而在 char c2 后浪费了 2 个字节的空间

而这就是因为受到了结构体对其数的影响

三.如何计算对齐


首先得掌握结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为 0 的地址处
  2. 其他成员变量要要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值(VS中默认的值为8 )
  3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

我们具体拿结构体 S1 来进行演示说明

第一步:

       第一个成员在与结构体变量偏移量为0的地址处


第二步:

       放置 int i 大小为 4 个字节和 VS 默认的对齐数 8 相比,取较小的数 4,所以下一个元素 int i 对齐到从起始位置数第 4 个单元的位置


第三步:

       放置 char c2 数据,char 大小为1个字节和 VS 默认的 8 相比,取较小的数 1 ,对齐数就是 1



第四步:

       结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍,在这个结构体里面,3 个成员的大小分别为 1, 4, 1,取最大值 4,所以这个结构体的大小必须是 4 的整数倍,我们已经使用了 9 个字节了,那 4 的最小整数倍就是 12,所以结构体 S1 的总大小为 12

四.练习题

       这里博主留下俩道练习题,有兴趣的朋友们可以自己尝试算一算俩个结构体分别占多大的字节空间,对于题目的见解,也欢迎各位将自己的思路和答案打在评论区内,大家一起讨论学习

struct S3
{
  double d;
  char c;
  int i;
};
struct S4
{
  char c1;
  struct S3 s3;
  double d;
};

本次的分享就到此为止了,如果你有不同的见解,欢迎在评论区相互交流,感谢您的支持

目录
相关文章
|
5月前
|
存储 安全 数据库
阿里云服务器计算型、通用型、内存型主要实例规格性能特点和适用场景汇总
阿里云服务器ECS计算型、通用型、内存型规格族属于独享型云服务器,在高负载不会出现计算资源争夺现象,因为每一个vCPU都对应一个Intel ® Xeon ®处理器核心的超线程,具有性能稳定且资源独享的特点。本文为大家整理汇总了阿里云服务器ECS计算型、通用型、内存型主要实例规格族具体实例规格有哪些,各个实例规格的性能特点和主要适用场景。
阿里云服务器计算型、通用型、内存型主要实例规格性能特点和适用场景汇总
|
1月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
121 13
|
1月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
62 11
|
1月前
|
编译器 Go
探索 Go 语言中的内存对齐:为什么结构体大小会有所不同?
在 Go 语言中,内存对齐是优化内存访问速度的重要概念。通过调整数据在内存中的位置,编译器确保不同类型的数据能够高效访问。本文通过示例代码展示了两个结构体 `A` 和 `B`,尽管字段相同但排列不同,导致内存占用分别为 40 字节和 48 字节。通过分析内存布局,解释了内存对齐的原因,并提供了优化结构体字段顺序的方法,以减少内存填充,提高性能。
42 3
|
1月前
|
存储 Java 程序员
结构体和类的内存管理方式在不同编程语言中的表现有何异同?
不同编程语言中结构体和类的内存管理方式既有相似之处,又有各自的特点。了解这些异同点有助于开发者在不同的编程语言中更有效地使用结构体和类来进行编程,合理地管理内存,提高程序的性能和可靠性。
31 3
|
1月前
|
存储 缓存 Java
结构体和类在内存管理方面的差异对程序性能有何影响?
【10月更文挑战第30天】结构体和类在内存管理方面的差异对程序性能有着重要的影响。在实际编程中,需要根据具体的应用场景和性能要求,合理地选择使用结构体或类,以优化程序的性能和内存使用效率。
|
1月前
|
存储 缓存 算法
结构体和类在内存管理方面有哪些具体差异?
【10月更文挑战第30天】结构体和类在内存管理方面的差异决定了它们在不同的应用场景下各有优劣。在实际编程中,需要根据具体的需求和性能要求来合理选择使用结构体还是类。
|
6月前
|
弹性计算 安全 前端开发
阿里云服务器ECS通用型、计算型和内存型详细介绍和性能参数表
阿里云ECS实例有计算型(c)、通用型(g)和内存型(r)三种,主要区别在于CPU和内存比例。计算型CPU内存比1:2,如2核4G;通用型为1:4,如2核8G;内存型为1:8,如2核16G。随着技术迭代,有第五代至第八代产品,如c7、g5、r8a等。每代实例在CPU型号和主频上相同,但性能有所提升。实例性能参数包括网络带宽、收发包能力、连接数等。具体应用场景如计算型适合高网络包收发、通用型适合企业级应用,内存型适合内存数据库等。详细信息可参阅阿里云ECS页面。
382 0
|
5月前
|
存储 缓存 安全
阿里云服务器实例规格选择参考:经济型、通用算力型、计算型、通用型、内存型区别
当我们在通过阿里云的各种活动选择云服务器实例规格的时候会发现,相同配置的云服务器往往有多个不同的实例可选,而且价格差别也比较大,这会是因为不同实例规格的由于采用的处理器不同,底层架构也有所不同(例如X86 计算架构与Arm 计算架构),因此不同实例的云服务器其性能与适用场景是有所不同。目前阿里云的活动中,主要的实例规格可分为经济型、通用算力型、计算型、通用型、内存型,对于很多初次接触阿里云服务器的用户来说,了解他们之间的差别就是比较重要的了,下面小编来为大家简单介绍下它们之间的区别。
阿里云服务器实例规格选择参考:经济型、通用算力型、计算型、通用型、内存型区别
|
4月前
|
存储 Go
Go 内存分配:结构体中的优化技巧
Go 内存分配:结构体中的优化技巧

热门文章

最新文章