《C语言深度解剖》(14):结构体内存对齐(详细配图讲解)

🤡博客主页:醉竺

🥰本文专栏:《C语言深度解剖》

😻欢迎关注:感谢大家的点赞评论+关注,祝您学有所成!


✨✨💜💛想要学习更多C语言深度解剖点击专栏链接查看💛💜✨✨ 


目录

1. 结构体内存大小计算(引例) 

2. 结构体内存对齐规则 

2.1:对齐规则1 

2.2:对齐规则2 

2.3:对齐规则3 

 2.4:对齐规则4

3. 实战 


上一篇文章中我们学习了结构体的进阶,其中介绍了结构体内存对齐的规则,由于结构体内存对齐需要讲解的篇幅较长,所以这里专门写了一篇文章来讲解。感兴趣的可以先阅读这一篇文章:

《结构体进阶学习》icon-default.png?t=N7T8https://blog.csdn.net/weixin_43382136/article/details/138768281

1. 结构体内存大小计算(引例) 

下面实例中结构体的类型你觉得是多大? (Visual Stdio环境下)

#include <stdio.h>
struct Stu
{
	char name;
	int age;
};

int main()
{
	printf("%d", sizeof(struct Stu));
	return 0;
}

初学结构体的人会认为,结构体类型的大小是其中各变量的大小之和,上述代码中结构体是 5 字节,其实并非如此!下面是运行结果: 8 (字节)

为什么输入结果是8而不是5呢?这与结构体在内存中特殊的存储方式有关,接下来就引出我们本章的主题 《结构体内存对齐》

2. 结构体内存对齐规则 

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

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

    对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

  • VS中默认的值为8
  • GCC环境下没有默认对齐数,此时结构体成员自身的大小就是对齐数

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。 

上述规则猛的一看会有点懵,什么跟什么啊?请继续往下阅读。

2.1:对齐规则1 

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

偏移量:结构体变量中第一个成员的地址 相对于首地址的距离。

对齐规则1中偏移量为0,就代表着结构体变量中第一个成员,是从开辟的整个结构体变量空间的首地址开始存储。

这里我们用以下结构体作为一个例子:下面结构体变量的大小为12字节

struct S1
{
	char c1;
	int i1;
	int i2;
};

我们一步步画图来分析 :

c1 存储位置

2.2:对齐规则2 

  • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

VS中默认的值为8

GCC环境下没有默认对齐数,此时结构体成员自身的大小就是对齐数

1. 当前是VS环境下,默认对齐数是8,后面两个成员分别是 int i1, int i2,它们都是4字节,因此在VS环境下,这两个成员变量的对齐数 就是 “4”

2. 根据规则2,其他成员变量要对齐到 "对齐数"的整数倍地址处,已知后面两个成员 i1 和 i2 对齐数是 4 ,这个规则意味着,i1 和 i2 要从偏移量为 4 的整数倍位置开始存储。具体看下图:

同理 i2 也是从 偏移量为 4 的整数倍位置开始存储,这里由图可知,需要从偏移量为 8 的位置开始存储,如下图所示:

而偏移量为“1,2,3”的空白处则会  

2.3:对齐规则3 

  • 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。 
struct S1
{
	char c1;
	int i1;
	int i2;
};

 对于上述的结构体例子,应用到规则3,其实就已经结束了,因为规则4是针对嵌套结构体的。

规则3含义:

  1. 当结构体中的最后一个成员被正确存放后,结构体的总大小并非简单地等于从第一个成员(偏移量为0的位置)到最后一个成员最后一个字节的长度。
  2. 而是首先判断出所有成员中对齐数中的最大对齐数,c1对齐数是 1,i1 和 i2 对齐数都是 4,因此整个结构体成员中的最大对齐数是 4.
  3. 最后,如果 从第一个成员(偏移量为0的位置)到最后一个成员最后一个字节的长度不是 最大对齐数 4 的整数倍,则整个结构体占据的总内存需要从最后一个字节继续延伸,直到整个结构体大小是 4 的整数倍。

上个例子中,最后一个成员 i2 成员存储好之后,最后一个字节的位置已经在 偏移量为 11 的位置处了,此时整个结构体变量的总大小已经是 12 了,12是 最大对齐数 4 的整数倍了,所以无需延伸,上述结构体S1类型的总大小就是12字节。 

 2.4:对齐规则4

  • 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。  

对齐规则4 其实跟 对齐规则3类似,只不过一个判断成员变量的对齐数,一个是 整个结构体的最大对齐数。

这里我们看一个新的例子:

S2结构体大小为 20 字节

struct S1
{
	char c;
	int i1;
	int i2;
};

struct S2
{
	char a;
	struct S1 s1;    //嵌套结构体
	char b;
};

3. 实战 

接下来会再整一个综合的例子,不再做出详细解释,看图分析即可。

S1的内存分布:

a的对齐数是4,b的对齐数是1,d的对齐数是8,因此 S1整个结构体的最大对齐数是8,总体大小为16字节。 

S2的内存分布: 

ch 的对齐数是1,s1 的对齐数是8, i 的对齐数是4,因此S2结构体类型最大对齐数是8.

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C语言中,结构体内存对齐是为了提高存储器的访问效率。结构体的成员在内存中的布局可能会按照一定规则进行对齐,以保证访问成员时的效率和正确性。 内存对齐是为了满足硬件对数据的访问要求,比如某些平台要求访问某些类型的数据必须从特定地址开始。此外,对齐也有助于减少内存碎片和提高内存的利用率。 在C语言中,默认情况下,结构体的成员按照其声明的顺序依次存放在内存中,但是编译器可能会在结构体中添加一些填充字节,以保证结构体的对齐要求。 编译器会根据结构体成员的类型和顺序来确定对齐方式,常见的对齐规则有以下几种: 1. 自然对齐:结构体成员按照其自身的大小进行对齐。例如,一个int类型的成员会按照4字节对齐。 2. 最大对齐:结构体成员按照其成员中最大类型的大小进行对齐。例如,一个结构体中有int和char类型成员,那么整个结构体会按照int类型的大小进行对齐。 3. 指定对齐:通过编译器提供的特定语法,可以手动指定结构体成员的对齐方式。 结构体的对齐方式可以通过编译器的相关选项进行配置,比如gcc编译器可以使用`__attribute__((aligned(x)))`来指定对齐方式,其中x表示对齐的字节数。 需要注意的是,结构体的对齐方式可能会因编译器、编译选项和目标平台而有所不同。因此,在编写跨平台代码时,应尽量避免依赖结构体的具体内存布局和对齐方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

醉竺

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

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

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

打赏作者

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

抵扣说明:

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

余额充值