【详解】结构体的内存对齐(每步配图)

目录

引言:

为什么存在结构体内存对齐?

结构体内存对齐规则:

练习一:

测试代码:

结果如下:

第二个练习:结构体的嵌套问题

测试代码:

代码结果如下:

两个关于结构体的易错点:

第一个易错点:

第二个易错点:结构的⾃引⽤

解决方法:

结语:


引言:

今天我们就要来学习一下考试经常考察的结构体内存对齐问题,相信有很多同学都被这个问题恶心过🤢,不过没有关系今天我会给你们讲清楚的,请各位系好安全带,我们要开始出发啦😃

为什么存在结构体内存对齐?

大部分的参考资料都是这样说的:

1. 平台原因 (移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要⼀次访问。假设一个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对齐是拿空间来换取时间的做法。 

介绍完原因后,接下来是结构体内存对齐的规则(重中之重,这里一定要弄懂啊!!!)

结构体内存对齐规则:

1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处

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

对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。

- VS 中默认的值为 8

- Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。 

接下来为了帮助大家理解下面我给出几个实例大家可以自己手算

练习一:

因为c1是char类型1个字符,系统给的对齐数为8,和1相比取小的,c1的对齐数为min(1,8)所以在哪开始都可以,i是int类型4个字节要从它的整数倍开始,所以只能从min(4,8)开始,c2在哪都可以开始,最后不要忘了第三点结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。这里特别注意是总大小,不是最大下标,是最大下标加一。故最后下标到11位置,图解如下:

c1用蓝色表示,浪费的地址为白色,i为红色,c2为绿色

测试代码:

#define  _CRT_SECURE_NO_WARNINGS 1
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
struct S1
{char c1;int i;char c2;
};
int main()
{int t = sizeof(struct S1);printf("%d", t);
}

结果如下:

第二个练习:结构体的嵌套问题

解决这个问题后,大家结构体内存对齐问题就没有问题啦,大家快快算算看🙌

//练习2-结构体嵌套问题
struct S3
{
    double d;
    char c;
    int i;
};
struct S4
{
    char c1;
    struct S3 s3;
    double d;
};
printf("%d\n", sizeof(struct S4));

解释如下:c1跳过,既然要计算s3,那么我们就要返回S3中,先算s3的内存占多大,d为double类型8个字节min(8,8),0是8的整数倍,c随便,i对齐数为min(4,8),9不是4的倍数,故跳到12,最后算下来s3占的字节数为16图解如下。

计算完s3,我们终于可以计算s4了,s3的填入看看我们对齐规则的第四点:4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。在本题结构体成员的成员中最大对齐数为d的8,故s3的对齐数为8,d为min(8,8),最后别忘了,第三点:3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对齐数中最⼤的)的整数倍。

总图解如下:(c1蓝色,s3绿色,d红色,白色为浪费空间)

测试代码:

#define  _CRT_SECURE_NO_WARNINGS 1
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
//练习4-结构体嵌套问题
struct S3
{double d;char c;int i;
};
struct S4
{char c1;struct S3 s3;double d;
};
int main()
{printf("%d\n", sizeof(struct S4));return 0;
}

代码结果如下:

补充一个小知识:编译器的默认对齐数是可以自己修改的,c语言就是这么霸道

#pragma这个预处理指令,可以修改编译器的默认对齐数。用法如下:要加一个pack()

#define  _CRT_SECURE_NO_WARNINGS 1
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{char c1;int i;char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{//输出的结果是什么?printf("%d\n", sizeof(struct S));return 0;
}

到这我就已经把结构体的对齐给你讲清楚了(大家一定要自己算算),考试遇到直接给它喵了!!!

两个关于结构体的易错点:

关于结构体为了防止大家出错,这里我给大家总结出来两个易错点供大家参考,大家看看自己有没有遇到这些情况,遇到了又该如何解决呢?下面我将带大家避免掉入这些坑。

第一个易错点:

大家先看看下面这个代码合不合法

struct
{int a;char b;float c;
}x;
struct
{int a;char b;float c;
}a[20], * p;
//下面这个合法吗
*p = x;

我们可以看到这是因为没有给结构体命名导致的争议,其实这是非法的,因为这两个结构体是不同的🙅‍,也就是说这两个结构体不是同一个类型的,所以匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使用一次。

第二个易错点:结构的⾃引⽤

下面这个代码合法吗?🐱‍🏍

如果正确的话那么sizeof(struct Node)的值是多少?

很明显这是非法的,因为这样sizeof(struct Node)的值是无穷的,就好像递归没有出口一样

正确引用如下:

我们可以看到这就是类似链表洛

struct Node
{
    int data;
    struct Node* next;
};

解决方法:

定义结构体不要使用匿名结构体了(好习惯要记住哟!!!)

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/618075.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JUC】JAVA线程小结

Java线程 前言——阅读10-20分钟&#x1f386;1.创建和运行线程ThreadRunableFutureTask多个线程运行方式 &#x1f4e3;2.不同操作系统查看进程线程的方法windowslinuxJava命令行 &#x1f680;3.java线程运行原理栈与栈帧线程上下文切换&#xff08;Thread Context Switch&am…

突然就爆火了!一张“旧纸”卖45元,这是什么操作?

没想到&#xff0c;一张“旧纸”竟然能卖到45元&#xff01;这可真是让人大跌眼镜。最近&#xff0c;有网友发现2024年的公历日历和1996年的完全一样。于是&#xff0c;网络上就掀起了一股“买本旧日历过新年”的热潮。那些挂出1996年老日历的卖家们&#xff0c;简直就像捡到了…

《 乱弹篇(二)》

题记 昨&#xff08;2024年1月12日&#xff09;天&#xff0c;既然笔者因感到写时评文力不从心&#xff0c;新辟一专栏《乱弹篇》&#xff0c;开始了“ 东西南北&#xff0c;古今中外&#xff0c;谈而不乱&#xff0c;抒怀而已”的写作路径&#xff0c;就要走下去&#xff0c;…

Windows使用(版本8.11)ElasticSearch、elasticsearch-head、kibana

下载安装引用这篇文章 目录 1、ES基本知识核心术语核心概念倒排索引ES字典树ES怎么保证读写一致 2、Window启动ES步骤elasticsearch-8.11.3elasticsearch-head-masterkibana-8.11.3 3、Kibana 调用ES API示例 1、ES基本知识 核心术语 ● 索引&#xff1a;index &#xff08;相…

Debezium发布历史64

原文地址&#xff1a; https://debezium.io/blog/2019/07/12/streaming-cassandra-at-wepay-part-1/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 在 WePay 上流式传输 Cassandra - 第 1 部分 七月 12, 2019 …

MathType绝对是我数学编辑的首选工具!

去年&#xff0c;微软曾说&#xff0c;要去掉Office里的公式编辑器&#xff0c;建议用户使用MathType编辑公式。目前Office用户可以到微软官网安装MathType的插件&#xff0c;现在免费使用&#xff0c;以后要收费。Word里安装这个插件以后&#xff0c;就会出现MathType的菜单。…

Spark避坑系列一(基础知识)

大家想了解更多大数据相关内容请移驾我的课堂: 大数据相关课程 剖析及实践企业级大数据 数据架构规划设计 大厂架构师知识梳理:剖析及实践数据建模 剖析及实践数据资产运营平台 Spark作为大数据领域离线计算的王者,在分布式数据处理计算领域有着极高的处理效率,而Python作为…

Camunda Sub Process

一&#xff1a;内嵌子流程 repositoryService.createDeployment().name("内嵌子流程").addClasspathResource("bpmn/embed_sub_process.bpmn").deploy(); identityService.setAuthenticatedUserId("huihui"); ProcessInstance processInstance …

汽车级线性电压稳压器LM317MBSTT3G:新能源汽车的理想之选

LM317MBSTT3G是一款可调三端子正向线性稳压器&#xff0c;能够在 1.2 V 至 37 V 的输出电压范围内提供 500 mA 以上的电流。此线性电压稳压器使用非常简便&#xff0c;仅需两个外部电阻即可设置输出电压。另外&#xff0c;它采用内部电流限制、高温关断和安全区域补偿&#xff…

whistle代理+mock轻松解决“页面端“测试接口没数据难题

0、whistle是什么&#xff1f;怎么用&#xff1f; 自行百度&#xff0c;此处不再赘述&#xff01; 1、示例演示&#xff08;交易订单测试&#xff09; 背景和痛点最近在测试一个小需求&#xff0c;需要涉及订单侧服务商品库侧服务库存侧服务财务侧线下交易服务。痛点主要在订…

redis夯实之路-键过期与发布订阅详解

设置键的生存时间或过期时间 Setex&#xff08;单位s&#xff09;&#xff0c;expire&#xff08;s&#xff09;&#xff0c;pexpire&#xff08;ms&#xff09;可以设置键的生存时间&#xff0c; Expirate&#xff0c;pexpirate设置键的过期时间&#xff08;timestamp的时间…

【降龙算法】基于QT插件机制实现一个机器视觉算法小框架

机器视觉行业有各种各样的拖拉拽框架&#xff0c;也叫做低代码平台&#xff0c;例如国内海康的VisionMaster&#xff1a; 一个机器视觉框架需要包含各种算法模块&#xff0c;日志窗口&#xff0c;图像显示窗口等等&#xff0c;【降龙算法】就是做了一个入门级的机器视觉算法框…

(核心变量)全国上市公司对外开放程度+dofile+参考文献(2000-2022年)

上市公司的对外开放程度数据反映了这些公司在国际市场上的活跃度和全球化程度。这包括了它们的国际贸易参与度、跨国投资和合作、国际市场的营销和品牌推广策略&#xff0c;以及在不同国家和地区的业务布局。此外&#xff0c;这段时间内不同行业和公司的对外开放程度可能有明显…

代码随想录算法训练营第七天|哈希表理论基础,454.四数相加II ,383. 赎金信 ,15. 三数之和 ,18. 四数之和

刷题建议 刷题建议与debug 代码随想录目前基本都有了视频讲解&#xff0c;一定要先看视频&#xff0c;事半功倍。写博客&#xff0c;将自己的感悟沉淀下来&#xff0c;不然会忘大家提问的时候&#xff0c;记得要把问题描述清楚&#xff0c;自己在哪一步遇到了问题&#xff0c…

记录一个Insert姿势引起的MySQL从库上查不到数据的问题

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 问题描述&#xff1a; 某测试环境的MySQL用了两台节点&#xff0c;主从同步结构。忽然有研发同学反映说MySQL的主从不同步了。他…

大数据技术原理与应用期末复习(林子雨)

大数据技术原理与应用期末复习&#xff08;林子雨&#xff09; Hadoop的特性HBase编程实践NoSQL的四大类型键值数据库优点&#xff1a;缺点&#xff1a; 列族数据库优点&#xff1a;缺点&#xff1a; 文档数据库优点&#xff1a;缺点&#xff1a; 图数据库优点&#xff1a;缺点…

超声波眼镜清洗机清洗眼镜会有伤害吗?适合洗眼镜超声波清洗机

眼镜作为日常生活中不可或缺的辅助视力工具&#xff0c;经常需要清洁保养以确保视力清晰和舒适佩戴。随着科技的发展&#xff0c;超声波眼镜清洗机成为越来越受欢迎的清洁方式。然而&#xff0c;很多人可能会担心使用超声波清洗机是否会对眼镜造成损害。但是可以很可以的告诉大…

设计模式——原型模式(Prototype Pattern)

概述 原型模式(Prototype Pattern)&#xff1a;使用原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。原型模式的工作原理很简单&#xff1a;将一个原型对象传给那个要发动创建的对象&#xff0c;这个要发动创建的对象…

C1-3.4 多个样本的向量化

C1-3.4 多个样本的向量化 1、为什么要用样本的向量化呢&#xff1f; 总结一句话&#xff1a;计算方便 下图是神经网络计算的步骤&#xff0c;右侧 是有一个输入变量a[0]&#xff08;什么是X呢&#xff0c;因为输入层有三个神经元&#xff0c;说明有三个输入变量&#xff0c;…

15 个适用于 Windows 的 PDF 解锁工具大全

PDF&#xff08;便携式文件格式&#xff09;是一种文件格式&#xff0c;用于呈现和交换任何独立于任何软件、硬件或操作系统的可靠访问的文档。Adobe 发明了它&#xff0c;但现在它是由国际标准化组织 (ISO) 维护的开放标准。因此&#xff0c;您现在必须了解这些 PDF 解锁工具。…