如何计算结构体的字节大小?结构体内存对齐详解

举报
luming_02 发表于 2024/02/24 23:33:07 2024/02/24
【摘要】         前言:在笔者看来,C/C++相对于其他高级语言来说,最传神的一点就是对于内存空间的精准分配,C/C++给予了程序员们很大的权力去手动管理内存。对于内存进行更好的管理可以从本质上提高我们程序的运行效率,而管理内存的前提条件则需要我们深刻的理解内存的分布,在阅读完本篇文章后,相信你一定能够更好的理解C/C++中内存分布的奥妙。一:内存对齐的引入我们先看一组C/C++代码并且思考思...

        前言:在笔者看来,C/C++相对于其他高级语言来说,最传神的一点就是对于内存空间的精准分配,C/C++给予了程序员们很大的权力去手动管理内存。对于内存进行更好的管理可以从本质上提高我们程序的运行效率,而管理内存的前提条件则需要我们深刻的理解内存的分布,在阅读完本篇文章后,相信你一定能够更好的理解C/C++中内存分布的奥妙。


一:内存对齐的引入

我们先看一组C/C++代码并且思考思考会输出什么:

//结构体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));

我们可以看到俩个结构体的成员类型都是一模一样的:

  • c1 都是 char 类型
  • c2 都是 char 类型
  • i  都是int 类型

唯独不同的是成员直接的相互顺序不同,按道理来说应该输出的是同一个值,那结果真是这样吗,我们继续往下走

令人意外的一点是,我们输出的结果完全不一样,一个是 8 一个是 12 ,出现这样的结果是为什么呢?为什么结构体之间成员的顺序不同就会导致结构体的大小不同呢?这中间差的 4 又是差在哪呢?

为了解决上述的问题,就需要介绍到“结构体内存对齐”的概念了


二.内存对齐的探究

为了更加方便我们观察结构体内部的细节,我们需要使用到 offsetof宏 来进行观察

我们可以打开cpp官网:offsetof - C++ Reference (cplusplus.com)

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

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

我们可以根据上述的输出结构画出对应的内存结构图:

我们使用同样的方法处理结构体2

	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

以上就是对于结构体内存对齐的具体计算


四.Test

这里笔者给出俩个结构体,大家可以自己进行计算

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



本次分享就到此为止了

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。