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

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

3天内不再提示

在MCU编程中局部变量赋初始值的重要性

jf_pJlTbmA9 来源:瑞萨MCU小百科 作者:瑞萨MCU小百科 2023-10-16 18:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

C语言编程过程中,由于计算需要,会使用各种各样的变量,用于给需要访问的地址取个名称,方便编程中使用,代码维护者也容易理解。

这里先给大家分享一个案例,让大家意识到变量赋初始值的重要性。

某用户在基于瑞萨MCU:RA6T2做开发时,发现一个问题,MCU发出的CAN数据帧总是莫名其妙的出错,比如应用中明明只使用了CAN的扩展帧,但是使用捕捉工具总是能捕捉到远程帧,出现远程帧的情况毫无规律可言,有时添加一个定时器中断,该现象就不会出现了,有时修改了代码里某处跟CAN没有任何关系的代码,该问题又会出现,过了两周时间调试无果。在介入Debug时发现,他使用的是CAN扩展帧,扩展帧使用29位ID标识符,而且对ID区数据定义了一个如下结构体:

wKgaomUD5XKAKA7FAAAHACC9mOU044.png

他在需要发送CAN帧时,申请一个如上结构体的临时变量can_id,在把can_id.id赋值后,再把该变量的地址传递给CAN的发送函数,在发送函数里使用如下语句把id的数据写入CAN的发送消息缓冲寄存器

wKgaomUD5XOAApX2AAAHaPYEckQ954.png

如下图,其中第30位的0表示数据帧,并不是远程帧,31位的1表示扩展帧。

wKgZomUD5XWAca2cAADiCZqaiwY457.png

用户是把can_id的所有数据赋值给了CFDTMID0寄存器,假如can_id.dummy中第二个位是1,会有什么后果呢?CFDTMID0.TMRTR=1,即CAN会发送远程帧。

用户又问:我没有给dummy赋值啊,为什么dummy的第二个位会变成1呢?这就是问题所在了,就是因为他没有给can_id.dummy赋值,所以can_id.dummy有可能为任意的值。下面详细分析一下,为什么这个局部变量的值会随意变化。

大家知道,变量根据存储类型和用途,一般可以分成:全局变量和局部变量。全局变量,就是指分配了固定地址的变量,全局变量可以在整个代码范围内使用。我们在申请全局变量时,有时对它赋一个初始值,也时也不会赋初始值,在代码上可能看不出有什么区别,但是编译器在编译程序时,是区别对待他们的。对于有初始化的变量,编译器还需要在Code Flash里(代码存储区)分配一段空间,把变量的初始值全部存储在该区域里,并且在MCU的启动代码里插入一段程序,把这些Code Flash区的初始值拷贝到变量对应的RAM地址中。假如上面的can_id是全局变量,并且申明变量的同时并按下图赋初始值:

wKgaomUD5XeAaBPmAAAqgT5kmag262.jpg

这时can_id.dummy=0,如果代码中用户没有再赋值,它的值也不会变化,这样就不会发生用户的那个远程帧的问题了。对于没有赋初始值的全局变量,编译器只是分配RAM的地址,并不会修改RAM地址里的数据,那么这个变量的值就会依赖于MCU启动时RAM里的值了。为了避免未赋值的全局变量出现上述的问题,我们一般会在MCU启动代码里插入未赋初始值全局变量的清零操作,相当于做了一个未赋初始值的全局变量的初始化赋值操作。

像上面的案例,can_id申请的是局部变量,这又是什么情况呢?

因为MCU的RAM资源有限,为了最大限度的利用RAM,MCU会提前分配一块RAM区域,叫堆栈区,这块区域大家共用,对于只需要在某个函数内使用的变量,引入了局部变量概念。在开始执行该函数时,才从堆栈里分配地址给局部变量使用,函数执行结束后,该变量占用的RAM区域被堆栈回收,当下次再调用该函数,再重新分配RAM。因此对于局部变量,每次申请到的地址是不同的,该地址很可能是其它函数使用过并改写数据了的,因此每次函数调用时can_id.dummy的数据是不确定的。因为堆栈区里的数据是被反复利用的,即使MCU的初始化代码对堆栈区域做清零处理,也是没有意义的。

由此看来,局部变量在申请的时候赋一个初始值,是非常有必要的。虽然有时候赋初始值没有用,但是出现问题时常常是致命的,而且也是非常难以定位的,你可能觉得我的代码里后面肯定会赋值的,但是后面维护该项目的其他工程师并不一定意识到这一点。像类似上面的案例,我在其他用户当中也是经常见到的。因此软件工程师在编程的时候,一定要养成局部变量赋初始值的习惯。

来源:瑞萨MCU小百科
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理

审核编辑 黄宇

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

    关注

    147

    文章

    19160

    浏览量

    404547
  • CAN
    CAN
    +关注

    关注

    59

    文章

    3097

    浏览量

    473560
  • 编程
    +关注

    关注

    90

    文章

    3724

    浏览量

    97455
  • 变量
    +关注

    关注

    0

    文章

    616

    浏览量

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

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    高光谱视觉检测中光源的重要性

    高光谱视觉检测中光源的重要性
    的头像 发表于 03-20 17:31 184次阅读
    高光谱视觉检测中光源的<b class='flag-5'>重要性</b>

    如何规范用、但不滥用局部变量(Local Variable)

    前面已产生的(读局部变量相对安全)。 UI刷新:把计算结果分发到多个显示控件(尤其事件结构里,集中计算后分发显示)。 临时过渡:重构旧代码时短期使用,之后应回到线传递或架构化方式。 不建议
    发表于 02-04 08:42

    关联使能VP时为何改变VP默认初始值?控件关联了使能VP变量,为何默认不是0?

    关联使能VP时为何改变VP默认初始值?控件关联了使能VP变量,为何默认不是0?
    发表于 02-03 14:19

    堆栈的原理揭秘

    局部变量的大小,将堆栈寄存器esp的下移,即可留出对应的空间用于存储该变量。而删除时,只需要将当前ebp的给esp【即将栈顶指针直接压
    发表于 01-23 07:08

    传递、指针传递、引用传递介绍

    进行操作,也就是说,即使形参的发生改变,实参的也完全不受影响。   2、指针传递:指针传递其实是传递的一种,它传递的是地址。传递过程中,被调函数的形参作为被调函数的
    发表于 01-21 06:48

    工业配电系统中局部放电在线监测技术的应用研究

    摘要 随着工业用电规模的持续扩大,中压配电系统保障企业连续生产中的重要性日益凸显。开关柜作为工业配电系统的关键节点,其内部绝缘状态直接影响供电安全与运行可靠局部放电作为绝缘劣化的
    的头像 发表于 01-14 10:28 297次阅读
    工业配电系统<b class='flag-5'>中局部</b>放电在线监测技术的应用研究

    C语言编程-局部性原理

    使用的磁盘块。 应用程序 局部性原理应用程序的设计中也扮演着重要角色。例如,Web浏览器将最近被引用的文档放在本地磁盘上。 对程序数据引用的局部性通过举例来说明程序的
    发表于 01-07 06:01

    嵌入式C语言中各变量存储位置

    局部变量局部静态变量、全局变量、全局静态变量区别如下: 局部变量: 栈区;
    发表于 12-25 07:54

    C语言全局变量重点使用

    重要的循环中我们不建议使用全局变量。 如果函数过多的使用全局变量,比较好的做法是拷贝全局变量局部
    发表于 12-12 06:58

    智能显示模块怎么显示工程中给寄存器设置初始值?我想给变量一个上电的默认该如何设置?

    智能显示模块怎么显示工程中给寄存器设置初始值?我想给变量一个上电的默认该如何设置?
    发表于 12-11 09:54

    第7章 变量进阶与点阵LED(7.1 7.2)

    知识——变量的作用域和存储类别。 7.1变量的作用域 所谓的作用域就是指变量起作用的范围,也是变量的有效范围。变量按他的作用域可以分为
    的头像 发表于 12-10 16:25 504次阅读

    智能显示模块怎么显示工程中给寄存器设置初始值?我想给变量一个上电的默认该如何设置?

    智能显示模块怎么显示工程中给寄存器设置初始值?我想给变量一个上电的默认该如何设置?
    发表于 12-06 10:20

    常用变量的介绍

    extern:用在全局变量上表示该变量在其他文件中已经定义;用在函数上作用同全局变量; static:用在全局变量上,和非静态全局变量相比,
    发表于 11-21 07:05

    C语言开发单片机为什么大多数都采用全局变量的形式?

    单片机的芯片资源从来都是 “精打细算” 的级别,CPU 主频普遍不高,RAM 总容量本就紧张,分给栈空间的更是少得可怜。要是像普通软件那样,依赖函数返回传递数据、频繁用局部变量周转,一来二去占用
    的头像 发表于 11-12 14:29 571次阅读
    C语言开发单片机为什么大多数都采用全局<b class='flag-5'>变量</b>的形式?

    按照芯来文档设置可以通过segger IDE debug了,但是没法看全局或者局部变量值,怎么解决?

    如题,按照芯来文档设置可以通过segger IDE debug了,但是没法看全局或者局部变量值,很麻烦。有遇到过解决了的吗?
    发表于 10-20 09:20