当前位置: 首页 > news >正文

C语言:结构体的内存对齐方式

结构体内存对齐

  • 1、引子
  • 2、内存对齐
    • 2.1、结构体成员的偏移量
    • 2.2、结构体内存对齐规则
    • 2.3、结构体内存对齐原因
    • 2.4、修改默认对齐数

1、引子

关于结构体的内存规则这一话题的研究我们可以通过计算结构体大小来引入。

例题:


#include<stdio.h>

struct stu1 
{
	char a;
	char b;
	int n;
};

struct s
{
	char a;
	int n;
	char b;
};

int main()
{
	printf("stu1:%zd\n", sizeof(struct stu1));
	printf("s:   %zd\n", sizeof(struct s));

	return 0;
}

从题中可以看出,结构体stu1和s用有相同的变量,只不过它们的创建顺序不一样,大家认为它们的结果各是多少呢?

结果:
在这里插入图片描述
只是创建顺序发生了变化,它们的结构体大小就不一样,所以我们可以推断,这两中结构体的内存创建过程肯定是不一样的。

2、内存对齐

2.1、结构体成员的偏移量

什么是偏移量呢?
偏移量是指变量距离首地址的距离,运用到结构体上就是结构体各变量距离结构体起始位置的距离。
在C语言中有一个宏,它可以计算偏移量,他就是offsetof,它在<stddef.h>头文件下,我们可以使用它来看一下。
以stu1为例
代码

#include<stdio.h>
#include <stddef.h>

struct stu1
{
	char a;
	char b;
	int n;
};

int main()
{
	printf("a:%d\n",offsetof(struct stu1,a) );
	printf("b:%d\n", offsetof(struct stu1,b));
	printf("n:%d\n", offsetof(struct stu1,n));

	return 0;
}

结果:
在这里插入图片描述
那这个结果又能说明什么问题呢?
我们可以画图说明:
在这里插入图片描述
我们根据它的偏移量可以画出这样一幅图,我们从图中可以发现0-7一共是8个字节,正好符合我们的结果。
我们从上图也不难发现,我们浪费了两个字节,这就和结构体的对齐规则有关。

2.2、结构体内存对齐规则

1、结构体的第一个成员对齐到和结构体变量的起始位置偏移量为0的地址处。详情可以看上图的变量a
2、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
对齐数: 编译器默认的一个对齐数(vs2022中默认是8)与该成员变量字节大小中的较小数。
(例如:在vs2022中假如在结构体中有int n,它是4个字节,比8小,那它的对齐数就是4).
3.结构体总大小为最大对齐数的整数倍
4、如果结构体中嵌套了结构体,结构体的整体大小,就是所有最大对齐数的整数倍(含嵌套结构体中的成员的对齐量)

练习1:

struct stu
{
	double s;
	char c;
	int n;
};

结果:16
在这里插入图片描述
其中它们最大的对齐数是8,而全部放入后总大小是16,是8的整数倍,不用改变。
练习2:

struct stu
{
	double s;
	int n;
	char c;
};

结果:16
虽然也是16,但是情况不同:
在这里插入图片描述
这种情况下,全部创建完成之后是13个字节,但最大对齐数是8,13不是8的整数倍,所以答案是16.
练习3:

#include <stdio.h>

struct s1
{
	int m;
	char g;
	short k;
};

struct stu
{
	double s;
	struct s1;
	char c;
};


int main()
{
	printf("%zd", sizeof(struct stu));

	return 0;
}

结果:24
这个就留给大家思考,我什么问题,在评论区留言,博主看到后会回复的。

2.3、结构体内存对齐原因

至于为什么会存在内存对齐
1.平台原因:
不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台上只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次。假设一个处理器总是从内存中取8个字节,那么地址必须是8的倍数。如果我们能保证将所有double类型数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读值或写值了,否则,我们可能要执行两次内存访问,因为对象可能被放在两个8字节内存块中。
总的来说:结构体的内存对齐,是拿空间来换取时间的。

2.4、修改默认对齐数

在C语言中默认对齐数也可以被修改。

#pragma pack(4)

这样就把默认对齐数修改为4了,再恢复之前的默认对齐数也很简单,只需再次添加语句就好只不过这次括号里不用添加数字。

#pragma pack()

这样就取消了。

好了,本期博客到这里就讲完了,
有什么疑问或者有什么看法在评论区留言哦,看到后会回复的。

我们下期博客再见~
(~ ̄▽ ̄)~

相关文章:

  • vite+react+ts如何集成redux状态管理工具,实现持久化缓存
  • MATLAB中asManyOfPattern函数用法
  • 代理对象中使用this
  • anolis8.9-k8s1.32-系统基本配置
  • Linux--基本指令2
  • 使用Python简单自动地生成图文并茂的网页文件(WEB数据可视化)
  • C# 类库打包dll文件
  • 操作系统之文件系统
  • 一次有趣的前后端跨越排查
  • MobileViTv3模型详解及代码复现
  • vscode接入ai插件(免费版)
  • 2025.3.1学习内容----网络编程
  • 蓝桥杯 门牌制作
  • 儿童英语启蒙规划
  • 分布式拒绝服务(DDoS)攻击检测系统的设计与实现
  • LeetCode:132. 分割回文串 II(DP Java)
  • 《论数据分片技术及其应用》审题技巧 - 系统架构设计师
  • 入门大模型的学习路线是什么?
  • Rt-thread源码剖析(2)——时钟与定时器
  • CAN总线通信协议学习4——数据链路层之仲裁规则
  • 专业做二手房装修网站/网站模板购买
  • 专业的镇江网站建设/哪些行业适合做网络推广
  • c可以做网站么/成都互联网公司排名
  • 怎么网站能找人做装修事/微信推广怎么弄
  • 一站式服务就像一个什么/百度经验app下载
  • 做网站平方根怎么表示/seo快速软件