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

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


审核编辑:刘清

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

    关注

    5068

    文章

    19014

    浏览量

    303192
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10824

    浏览量

    211126
  • C语言
    +关注

    关注

    180

    文章

    7598

    浏览量

    136161
  • 编译器
    +关注

    关注

    1

    文章

    1618

    浏览量

    49047
收藏 人收藏

    评论

    相关推荐

    ARM嵌入式系统中内存对齐的重要性

    做嵌入式系统软件开发,经常在代码中看到各种各样的对齐,很多时候我们都是知其然不知其所以然,知道要做好各种对齐,但是不明白为什么要对齐,不对齐会有哪些后果,这篇文章大概总结了内存
    的头像 发表于 11-11 17:17 506次阅读
    ARM嵌入式系统中内存<b class='flag-5'>对齐</b>的重要性

    你是否真的了解结构占用了多少字节?

    结构成员所占内存空间大小一般情况下,如果想知道结构成员的内存占用情况需要:1、先用结构在内
    的头像 发表于 06-04 08:04 377次阅读
    你是否真的了解<b class='flag-5'>结构</b><b class='flag-5'>体</b>占用了多少字节?

    深入理解 FPGA 的基础结构

    转载地址:https://zhuanlan.zhihu.com/p/506828648 文章很详细的介绍了FPGA的基础结构,能更直观的理解内部结构原理。对深入学习很有帮助。 以下是正文: 这一段
    发表于 04-03 17:39

    C语言结构史上最详细的讲解【软件干货】

    struct结构数据类型 前言 我们知道,在C语言中有一些基本的数据类型,如 char int float long double string(c99) 等等数据类型,他们可以表示一些事物
    的头像 发表于 03-28 17:52 689次阅读

    STM32关于FLASH的编程对齐错误标志位(PGAERR)的疑问求解

    大神们,我现在正在做一个应用,需要熟悉STM32F4的FLASH的任何错误标识,以用于特殊情况下的错误标识判断做相应处理,但是针对FLASH的编程对齐错误标志(PGAERR)与我理解不同。 原文
    发表于 03-22 07:59

    使用LSM6DSOWTR里面的temperature sensor,为什么temperature offset达到了±15℃的偏差

    你好,我们想使用LSM6DSOWTR里面的temperature sensor,但是看到规格书里面对temperature sensor的描述,temperature offset达到了±15℃的偏差,这个地方有点无法理解,这个
    发表于 03-15 07:59

    求助,关于G031ADC结构设置的几个疑问求解

    本人在使用ADC时想使用多通道模式,所以便在CUBEMX上将十九个通道全部打开(包括三个内部通道),生成代码以后详细看了一下结构的配置发现有几个疑惑, 1.ADC通道分为规则通道和注入通道,那么
    发表于 03-15 07:03

    求助,请问一个结构如何全部定义到 __attribute__ 区域?

    请问一个结构如何全部定义到 __attribute__ 区域? 例如我这里涉及到一些高速计算的缓存,计划将缓存数据存储到 __attribute__ 区域。 三个结构 ,每个
    发表于 01-16 07:29

    经典 C 语言编程,结构和联合体如何共用?

    结构 结构占用的内存大小,首先和编译器的系统位数有关系,类似于CPU是 64 bits 还是 32 bits 的情形;其次,结构
    的头像 发表于 01-11 18:24 1260次阅读
    经典 C 语言编程,<b class='flag-5'>结构</b><b class='flag-5'>体</b>和联合体如何共用?

    结构与指针的关系

    在C语言中,结构(Struct)是一种用户自定义的数据类型,它允许您将不同类型的数据项组合在一起,以便形成一个更复杂的数据结构结构可以
    的头像 发表于 01-11 08:00 938次阅读
    <b class='flag-5'>结构</b><b class='flag-5'>体</b>与指针的关系

    keil arm工程中结构1字节对齐如何实现

    在Keil Arm工程中,结构对齐方式可以通过使用特定的编译器指令或者关键字来实现。结构对齐
    的头像 发表于 01-05 14:40 3491次阅读

    ADE7858A测出来的有效值和实际值偏差有点大是什么原因导致的?

    尽管ADE7858A有校验,但校验前测出来的有效值和实际值偏差有点大,目前找不到原因,希望知道的专家能给予指导,谢谢各位! 具体数值如下: 输入的实际电压有效值为228v,但从VRMS寄存器里得到的数值换算后得到的值为217,相差11V,貌似
    发表于 12-26 06:03

    晶振频率偏差过大怎么办?教你如何解决晶振频率偏差过大问题

    晶振频率偏差过大怎么办?教你如何解决晶振频率偏差过大问题 晶振频率的稳定性对于许多电子设备的正常运行非常重要。频率偏差过大可能会导致时序错误、通信失败以及计时误差等问题。在本文中,我们将介绍晶振频率
    的头像 发表于 12-18 14:30 2090次阅读

    golang结构如何定义?如何使用呢?

    结构是go语言最重要的数据结构之一,go和其它编程语言不一样,它没有类的概念,类比过来struct就相当于其它语言中的类,因此十分重要。
    的头像 发表于 11-28 10:36 416次阅读

    golang结构实例代码

    结构是go语言最重要的数据结构之一,go和其它编程语言不一样,它没有类的概念,类比过来struct就相当于其它语言中的类,因此十分重要。
    的头像 发表于 11-28 10:35 424次阅读