0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

对结构体的对齐理解上有点偏差

冬至配饺子 来源:最后一个bug 作者:bug菌 2022-08-10 18:08 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

最近看到一些朋友在交流结构体对齐方面的一些问题,从他们的交谈中隐隐约感觉有几个朋友对结构体成员的对齐理解上有点偏差,不能说完全不对吧,毕竟这是老生常谈的问题了~

1、变量与内存

首先我们要明确,在嵌入式C语言中变量是什么?其实所谓的变量就是一小段内存。

当你随心所欲的在C程序中定义着各种变量,有没有想过他们是如何被安排到相应内存上的?

好吧,其实他们是怎么安排的,并不需要程序员太多的操心,这个映射过程都是编译器自动给大家分配的,(可以借助动态内存的角度去看待这个分配问题),因为大部分变量在一定内存区域上是可以任意选择地址的,比如你定义一个全局的int gVar 变量,在不进行特殊指定内存位置的情况下,其编译后所分配的内存地址并不一定每次都是相同的;当然,每次编译完成便会确定下来,并且程序中对该变量的访问,均会使用所确定下来的内存地址。

既然变量的地址分配过程由编译器自动完成,但有时候我们想把一些或者某个变量放在固定的内存地址处等,此时就需要通过一些语法来告诉编译器该如何分配这些指定变量内存的分配,比如要做复位数据恢复等。

然而内存的对齐问题也是对这些变量分配位置处理的一种方式,通常我们看到的align或者pack等就是来干预编译器的这块处理的。

2、结构体对齐

理解了上面的一个思路,那么我们来分析分析结构体对齐问题。

参考demo:

pYYBAGLzgjeAT8iJAAD1H7F0bjk340.pngpYYBAGLzgj2ARVKUAAC0Xb725aI681.png

运行结果:

poYBAGLzglmACdHRAAAwvobA02U713.png

以上编译结果采用的是32位编译器,默认对齐方式是4个字节,char类型占据1个字节,int占据4个字节,

下面简单分析一下结果:

1、默认方式,采用4个字节对齐,那么char后面需要填充3个字节,然后存放int类型,所以结构体大小输出为8。

2、1字节对齐方式,直接紧凑排列,很多人也叫不进行对齐处理,所以输出结果是5。

3、2字节对齐方式,其实和4个字节对齐是类似的,char按照2字节对齐,所以后面需要填充一个字节,这样int才能以两字节对齐排布,此时整个结构体占据6个字节。

4、4字节对齐方式与默认对齐方式一致,最后看看8字节对齐,此时char类型与int类型完全能够被8个字节容纳,而该结构体最大数据类型是4个字节,所以char后面会预留3个字节,进行4字节对齐,然后放置int类型,此时与4字节对齐是一致的。那么一些朋友会问,是不是在上面的8字节例子中再加入一个char类型的成员,整个结构体就会占据16个字节了呢?

pYYBAGLzgnOAR4kbAAA_oPyNI74889.png

其输出结果如下:

pYYBAGLzgpSARzfuAAAupVKITM0562.png

结构体所占据的字节是12个,那是不是认为8字节对齐没有意义呢?我们再看一个实验:

poYBAGLzgqeAFrKaAABIrxc_Zj4505.png

此时double占据了8个字节,按照前面的思路应该是4+8+4,应该最终结构体的大小是16个字节,而结果显示:

poYBAGLzgr6ABA9MAAAtrVniz38521.png

输出结果显示24=8+8+8的形式,大家也可以直接采用打印结构体成员地址的办法查看是几个字节对齐,有点晕,到底编译器这一块是怎么处理的呢?结论是:对齐字节数 = min<当前指定的pack值,最大成员所占字节大小>。

很多朋友其实研究到这个阶段基本上就没有再继续探究了~嵌入式C语言一定要跟硬件结合理解~

3、内存对齐

其实所谓的结构体对齐,并不是简单的1个字节、两个字节等多个字节的排列组合,而是在对应对齐地址上分布。首先对齐需要解决的问题是什么 ? 即为啥需要对齐?

提高内存的访问效率,也可以说是受CPU等硬件方面的限制,按照特定的对齐地址进行数据的访问要快于跨非对齐地址的内存访问;并且有些平台仅支持对齐方式访问,非对齐方式会直接运行错误。

poYBAGLzgteADWrAAABvtqExg18425.png

为了加快相关数据的正确访问,编译器会把相关的变量尽量的放到对齐的地址上,也就是默认的对齐方式,比如CPU在偶数地址上访问比较快,那么就会采用2个字节对齐的方式。
所以结构体内部成员并不是简单成员字节个数的对齐拼凑,而是让结构体成员落在对齐的地址上以便访问。如下图所示,当进行2字节对齐,如果只是简单的拼凑,两种分布都是可以的,但是左侧才是正确的2字节对齐方式,char成员变量的地址是2,int变量的地址是4,均为2字节的倍数。

pYYBAGLzgu6AXO9DAABqWWJvUDc646.png

总结一下: 结构体对齐不再是简单的字节个数的拼凑,而是要与内存地址进行挂钩~一般我们也可以理解为内存地址分配是多少字节的倍数,就是多少直接对齐~


审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5186

    文章

    20153

    浏览量

    328931
  • cpu
    cpu
    +关注

    关注

    68

    文章

    11218

    浏览量

    222964
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144625
  • 编译器
    +关注

    关注

    1

    文章

    1669

    浏览量

    51083
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    typedef结构使用

    虽然结构的出现能够让我们有一个更科学的数据结构来管理数据,但是每次使用结构都需要struct...,未免显得有些冗长和麻烦。有了type
    发表于 12-08 07:04

    共用声明

    共用也称联合体。 和结构还是有点像: union 共用名称 { 成员1; 成员2; 成员3; }; 但是两者有本质的不
    发表于 12-05 07:24

    为什么不建议用匿名结构

    说起匿名结构,想必大家第一感觉就是看着好高大上的名字,但实际上也就那样。 typedef struct { union { struct { uint8_t bit_0:1
    发表于 12-04 07:39

    C语言结构使用

    有时候需要将不同类型的数据组合为一个整体,以便于引用。例如,一名学生有学号、姓名、性别、年龄等属性,如果针对每个属性都单独定义一个变量,那么当有多名学生时变量就难以分清。结构就是用来管理不同类
    发表于 11-12 08:30

    电能质量在线监测装置能测频率偏差吗?

    电能质量在线监测装置 能测量频率偏差 ,且频率偏差是其核心监测指标之一,需符合《GB/T 15945-2017 电能质量 电力系统频率偏差》等国家标准,可实时跟踪电网基波频率(如 50Hz/60Hz
    的头像 发表于 10-13 17:48 478次阅读

    定义IO初始化结构

    由上述IOPORT相关功能的枚举类型我们可以知道,在对IOPORT模块进行初始化时需要根据情况配置它们。因此我们定义一个IOPORT初始化的结构类型IOPORT_Init_t,它的成员包括了由上述所有枚举类型所声明的变量,因此该结构
    的头像 发表于 07-16 16:26 1110次阅读

    渗压计在混凝土结构中的安装指南

    在现代土木工程和岩土工程中,渗压计是监测混凝土结构体内孔隙水压力变化的重要工具。南京峟思公司生产的渗压计因其高精度和可靠性而被广泛应用于各种工程监测项目中。一、渗压计在混凝土结构中的应用价值渗压计
    的头像 发表于 05-28 10:55 383次阅读
    渗压计在混凝土<b class='flag-5'>结构</b><b class='flag-5'>体</b>中的安装指南

    GLAD应用:全息光栅模拟

    用于模拟全息记录介质中形成的梯度折射率分布。全息结构一旦形成,就可以在传输过程中将一束入射光波逐渐转换成形成体全息结构的另一束光波。两束光波之间的能量传递转换效率与全息
    发表于 05-15 09:32

    Allegro Skill布局功能--器件丝印过孔对齐介绍与演示

    Allegro系统虽然提供了基本的元件对齐功能,但其适用范围较为有限。相比之下,Fanyskill 的“对齐”命令在操作体验和功能性上更具优势:其界面设计更加直观易用,并支持多种元素的对齐操作,包括
    发表于 05-14 08:59 2423次阅读
    Allegro Skill布局功能--器件丝印过孔<b class='flag-5'>对齐</b>介绍与演示

    C语言中结构与联合体的深度解析:内存布局与应用场景

    一、基础概念与核心差异 1.1 结构(Struct)的本质 **结构是C语言中实现数据封装的基石,其核心特征在于内存独立性。每个成员变量在内存中按声明顺序依次排列,形成连续的内存块
    发表于 04-08 09:18

    图解边沿对齐,中心对齐PWM(可下载)

    在说边沿对齐,中心对齐前,我们先来段铺垫,PWM 又称脉冲宽度调制,我们通过调 节脉冲的占空比,我们可以控制电压的大小(比如我们满占空比时电压为 12V,我们可以通 过调节占空比让电压变为 7V
    发表于 03-31 15:15 1次下载

    一种基于基础模型对齐的自监督三维空间理解方法

    三维空间理解是推动自动驾驶、具身智能等领域中智能系统实现环境感知、交互的核心任务,其中3D语义占据预测 (Semantic Occupancy Prediction) 对三维场景进行精准的素级建模。然而,当前主流方法严重依赖大规模标注数据,制约了模型的可扩展性和泛化能力
    的头像 发表于 03-18 15:01 746次阅读
    一种基于基础模型<b class='flag-5'>对齐</b>的自监督三维空间<b class='flag-5'>理解</b>方法

    晶振的频率偏差与解决方法

    晶振是一种常用的频率标准元件,在电子电路中具有重要的作用。然而,在实际使用中,晶振的频率并不是完全准确的,常常会存在一定的偏差。这种偏差是由多种因素造成的,包括温度变化、电压变化、机械应力和制造偏差
    的头像 发表于 02-21 14:53 1046次阅读
    晶振的频率<b class='flag-5'>偏差</b>与解决方法

    Orcad绘制原理图的元器件对齐方法

    在使用Orcad软件绘制原理图的时候,为了使原理图绘制的美观一些,有时候也希望像PCB设计一样,将所有的器件都进行对齐,这里我们给大家介绍下,原理图器件对齐的方法,方便大家在原理图设计的时候也可以将元器件进行对齐
    的头像 发表于 02-07 10:33 2566次阅读
    Orcad绘制原理图的元器件<b class='flag-5'>对齐</b>方法

    ADR4520的负载调整度有点偏差是什么原因引起的?

    的负载调整度有点偏差(应该是等效内阻大吧),所以准备用ADS1255资料推荐的OPA350做一级缓冲,不过发现有以下几个问题让我感觉到很困惑: 1.OPA350的失调电压居然高达1mV(这个数值可以
    发表于 12-18 06:56