工程中uint8变量文件比uint32变量文件大4字节的问题排查

前言

(1)如果有嵌入式企业需要招聘湖南区域日常实习生,任何区域的暑假Linux驱动实习岗位,可C站直接私聊,或者邮件:zhangyixu02@gmail.com,此消息至2025年1月1日前均有效
(2)今天在一个交流群看到一个有意思的问题,网友问:开发32位单片机,能够使用unsigned char 就不使用unsigned int,这样是否可以节约内存呢?
(3)当时我看到这个问题是懵的,uint8怎么会比uint32更节省空间呢?
(4)学习本文之前,需要先了解数据的内存分配知识,所以需要各位先了解这篇博客:
RAM明明断电会丢失数据,为什么初始化的全局变量存储在RAM?详细分析程序的存储

网友问题解决思路

(1)首先申明一下这位网友的测试环境,是在STM32F103中进行的相关测试。

问题

(1)这位网友在测试代码工程的时候,发现将unsigned char修改为unsigned int的时候,工程代码会减少4字节。

在这里插入图片描述
在这里插入图片描述

解决思路

(1)对于这个问题,很容易知道大体问题是在哪里。
<1>首先,这个是局部变量,他不会占用实际的空间,因此我们发现,实际变化的内存大小是在code段。
<2>其次,在32位的机器中,CPU寄存器都是32位的,因此在处理数据的时候,低于4字节数据会被提升到4字节再进行处理。
(2)那么,我们就可以大致的推断出,这个地方大概率是需要汇编指令进行字节提升,新增加的汇编指令导致code段增多了。
(3)既然有了上述的基础概念之后,就开始定位问题。
<1>第一步,查看map文件。我们需要知道,这个增加的汇编指令具体是在那个文件中。

在这里插入图片描述

<2>对比uint8uint32map文件中Image component sizes部分,我们能够发现,提升的4字节果然是在main.o中,因此此时就知道是在main.c中的在汇编阶段导致的汇编代码不同的问题。

在这里插入图片描述

<3>查看汇编,使用keil的Debug功能,能够帮我们看到汇编内容,直接在mian.c中开断点,对比汇编代码。我们能够发现,如果是uint32,只有一个BCC的指令,但是如果是uint8就是UXTBBLT

在这里插入图片描述

<4>既然知道的区别之后,开始研读这几条汇编代码,进行对比分析。因为这里是无符号数据的对比,所以说,BCCBLT其实是等效的。如果是有符号数据比较,那么就需要使用BLT。(这是arm汇编的内容,简单了解即可,不会的时候查谷歌、百度、chatgpt)

# uint8
UXTB   r4 , r0 ;将一个8位无符号字节零扩展为32位无符号整数,高位的24位填充为零
CMP    r4 , 0x64 ;将寄存器r4的值和0x64(十进制就是100)对比
BLT    0x0800aA8C ; 如果CMP指令的比较结果是负数(即r4<0x64),则跳转到0x0800aA8C 地址
# uint32
CMP    r4 , 0x64 ;将寄存器r4的值和0x64(十进制就是100)对比
BCC    0x0800aA8C ; 如果前一条CMP指令的比较结果没有产生进位(即r4>=0x64),则执行分支

<5>知道汇编代码的大致意思之后,此时就要考虑汇编代码的大小问题。通过询问chatgpt可知,这三条指令都是4字节,因此,当我们main.c中汇编之后多了一条汇编指令,code段就会增加4字节。

在这里插入图片描述

扩展测试1

问题

(1)我们发现,上面测试的都是局部变量,我们要不试试全局变量看看结果如何?
(2)我们能够发现两个有意思的问题:
<1>对比两个全局变量,我们会发现,生成的代码一模一样。
<2>对比全局变量和局部变量:code段增加了,rodata不变,rw增加4字节,zi段减少了4字节。(这个我也不会,苦笑。查了很久资料,也调了很久,不知道为啥怎么是这样的结果。应该是工程中某些细节影响,具体细节没排查到)

在这里插入图片描述

解决思路

(1)首先我们先看两个全局变量工程怎么会一模一样的。还是直接看map文件,通过对比map文件知道内存布局信息。
(2)我们能够发现main.o的RW-data确实少了3字节数据,但是呢,在(incl. Padding),RW-data却多了3字节数据。

在这里插入图片描述

(3)为什么在(incl. Padding),RW-data却多了3字节数据呢?查阅资料可知,编译器为了满足对齐要求而在数据或代码之间插入额外的填充字节。一般来说,字节对齐只有两种可能:
<1>硬件要求: 许多计算机体系结构对于某些数据类型的访问有硬件对齐的要求。例如,一些处理器可能要求访问特定大小的数据类型的变量时,其地址必须是该数据类型大小的倍数。如果不满足这些要求,可能导致性能下降或者引发硬件异常。如果是采用的冯诺依曼结构,不进行字节对齐,可能导致指令和数据弄混淆。
<2>性能优化: 计算机系统通常会将数据加载到寄存器中进行处理,而寄存器的大小通常是2的幂。如果数据类型的大小是寄存器大小的倍数,那么从内存加载数据到寄存器的操作就更为高效。字节对齐可以确保数据在内存中的地址是寄存器大小的倍数,提高访问速度。
(4)因为这里的测试平台是STM32F103,采用的是CM3内核,因此我打开CM3内核手册可知,寄存器的PUSHPOP永远是4字节对齐的。因此,这里是硬件层面要求进行字节对齐操作。因此,uint8uint32的全局变量产生的代码工程是一样的效果。

在这里插入图片描述

扩展测试2

问题

(1)上面我们发现,uint8和uint32的全局变量结果一模一样。那么我们尝试创建两个全局变量试试呢?
(2)结果发现,RW-data增加了4字节,ZI-data增加4字节。

在这里插入图片描述

解决思路

(1)依旧是看map文件,我们发现main.o的RW-data确实是从2字节变成了8字节,但是同时也少了2字节的字节对齐。因此RW-data是增加了4字节。

在这里插入图片描述

(2)看ZI-data,发现这里会增加4字节对齐,具体原因不清楚

在这里插入图片描述

总结

(1)关于uint8占用空间更多,还是uint32占用空间更多,这个取决于编译器的编译策略硬件特性性能优化。我们无法一概而论。正因如此,在目前内存不那么紧张的时代,不要过分的纠结于这个问题。什么时候用那个数据,就用那个,不要抱有心理负担。否则只会适得其反,拖慢研发速度。

参考

(1)CM3权威指南
(2)关于ARM中的tst、cmp、bne、beq指令
(3)用Keil生成bin、汇编、C与汇编混合文件,再也不想debug了!

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

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

相关文章

QCustomPlot(一)设置环境

1 设置QCustomPlot环境 将QCustomPlot与你的应用程序配合使用非常简单&#xff1a; 从下载部分获取最新版本的QCustomPlot。 像使用其他普通的类文件一样&#xff0c;使用qcustomplot.h和qcustomplot.cpp文件。 1.1 QtCreator用户 在左侧边栏中右键单击项目的根目录条目&a…

小程序js常用工具及请求关键代码的封装

一个js常用工具及请求关键代码的封装随着时间变迁。 一 2017年 第一版web管理后台在用 web后台管理页面用 /*** Created by hua on 2017/8/24.*/ var requestResult{success :0,failure:1,failureMsg:2 }jx{reqAjax:function (isSync,url,fnSuccess,fnFailure) {$.ajax({typ…

向日葵远程控制软件MySQL5.7的安装与配置

目录 一. 向日葵远程控制软件 1.1 简介 1.2 选择原因 1.3 安装及使用 1.4 使用场景 二. MySQL5.7 安装与配置 2.1 什么是MySQL 2.2 安装 MySQL5.7 2.2.1 安装步骤 2.2.2 内部连接 2.2.3 外部连接 三. 思维导图 一. 向日葵远程控制软件 1.1 简介 向日葵电脑版是一款拥有多年…

智能化校园:深入探讨云端管理系统设计与实现(一)

推荐阅读 轻松驾驭JDBC&#xff1a;一篇文章帮你搞定数据库连接 ChatGPT爆火一周年&#xff0c;快来拥有专属你的ChatGPT应用&#xff01; 文章目录 推荐阅读智慧校园云端管理系统的设计和实现项目简介项目技术栈项目功能项目开发项目搭建修改pom.xml文件项目包结构配置applic…

element-ui Tree 树形控件 过滤保留子级并获取过滤后的数据

本示例基于vue2 element-ui element-ui 的官网demo是只保留到过滤值一级的&#xff0c;并不会保留其子级 目标 1、Tree 树形控件 保留过滤值的子级 2、在第一次过滤数据的基础上进行第二次过滤 先看效果 Tree 树形控件 保留过滤值的子级 <el-treeclass"filter-t…

Redis(中)

1、redis的持久化 "Redis 如何将数据写入磁盘"&#xff0c;首先要明白的时候&#xff0c;我们使用的redis的数据保存在内存上的&#xff0c;也就是说&#xff0c;只要我们的电脑关机或者重启服务器&#xff0c;那么在内存中的数据就会消失&#xff0c;所以要想持久化…

网络四元组

文章目录 网络四元组 今天我们来聊聊 网络四元组 网络四元组 四元组&#xff0c;简单理解就是在 TCP 协议中&#xff0c;去确定一个客户端连接的组成要素&#xff0c;它包括源 IP 地址、目标 IP 地址、源端口号、目标端口号。 正常情况下&#xff0c;我们对于网络通信的认识可…

2024,这将是量子计算的真正挑战

2023年&#xff0c;一项项量子计算纪录被打破。 谷歌量子AI团队证明了将多个量子比特分组合成为一个逻辑量子比特的纠错方法可以提供更低的容错率。以往的纠错研究随着比特数的增加&#xff0c;错误率会提高&#xff0c;都是“越纠越错”&#xff0c;而这次谷歌首次实现了“越纠…

Vue3 结合typescript 组合式函数

在App.vue文件中 实现鼠标点击文件&#xff0c;显示坐标值 第一种方法 第二种方法&#xff1a;组合式函数 结果&#xff1a; 官网推荐组合函数&#xff1a;https://vueuse.org

[讲座] - 闲聊工业设计

1&#xff0c;工业设计相关的学科分类 2&#xff0c;工业设计的职业发展路线 3&#xff0c;工业设计师的成名人物 4&#xff0c;设计了可口可乐的Loewy 可口可乐的瓶子&#xff0c;无论白天晚上还是瓶子被打碎&#xff0c;都能认出这个是可口可乐的瓶子。 草图参照了可可豆&am…

项目引入Jar包的几种方式

目录 背景 方式一 前提 创建一个jar包 使用 方式二 背景 通常情况下&#xff0c;使用SpringBoot框架开发项目的过程中&#xff0c;需要引入一系列依赖&#xff0c;首选的就是在项目的 pom.xml 文件里面通过Maven坐标进行引入&#xff08;可以通过Maven的坐标引入jar包的前…

Java中的数据类型和操作符

目录 Java的数据类型&#xff1a; ! >>> ?: 数组另外一种传参形式&#xff1a; 输入&#xff1a; switch: 快捷键&#xff1a; 快捷创建包&#xff1a; 提交Gitee仓库&#xff1a; next和nextLine区别&#xff1a; 注意事项&#xff1a; 循环终…