加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 动态数组???
    •  
    • 防出去了昂
    •  
    • 有备而来
    •  
    • 寻根问底
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

这段代码不讲武德,劝你耗子尾汁

2020/11/23
172
阅读需 6 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

动态数组???

不知道你是否听说过 C99 有一个动态数组的特性,也就是说,数组大小可以根据需要动态的变化。

我们都知道,在 C89 模式下,数组的声明只能是这样:

但到了 C99,数组的大小可以用变量代替,根据需要变化:

有些人为了尝鲜或者为了使用方便,可能会在程序中写上类似的代码。一般情况下,代码运行很正常,没有一点问题。但在运行时间需要严格控制的情况下,这段代码就不讲武(码)德了。

 

防出去了昂

我们都知道,嵌入式系统的一大好处就是运行时间可控,是实时的系统,所以它可以做一些高实时性的工作,比如控制、采样等。

就拿采样来说,一般都会要求采样率,比如 100Hz、10Hz,换算到时间单位,就是需要 10 毫秒、100 毫秒读取一次数据,这个数据可能是内部寄存器(比如 ADC),也可能是外部的器件通过 I2CSPI总线获取,而一般来说,这些总线的通信时间是稳定的、可控的。但是有一天,你发现你的 SPI 驱动程序运行时间变得不再可控,它有时 50us 完成一次数据的采集,有时需要 1 ms 才完成,总之没有规律可循,唯一的规律就是,当系统全面开始工作时,这个时间大部分在 1 ms 以上,只有很少几次是几十微秒就完成了执行。

在 10 Hz 采样率下,1 ms 误差也不算太大,但当在 100 Hz 采样时,时间误差就是 10%,不可忽略你仔仔细细的查看了实现代码,发现就是简单的 SPI 通信,基本上都是判断、赋值操作,还有就是使用循环等待标志位(使用硬件 SPI)。(或许你会怀疑循环等等标志代码导致了时间的不确定,但我的第一直觉告诉我不是它,因为 SPI 的通信时间是可控的(只要器件正常,从机一定会返回数据),STM32F1 系列的硬件 SPI 通信鱼鹰也用了五六年,不应该有问题才对)这些我全部防出去了昂(甚至鱼鹰都考虑到线程执行可能受到中断的影响,特地在问题代码执行期间禁止了中断)。没办法,我只能停停,放下源码本身的分析,拿出了杀手锏:《KEIL 下如何准确测量代码执行时间?》开始对问题代码进行时间测量。

 

有备而来

经过几番测量,很快昂,定位到类似下面的代码:

发现竟然在 52 到 57 行之间花费了大量时间。就一些局部变量的定义,唯一和传统写法不同的是使用了动态数组,怎么会花费这么多时间?

按照传统写法,这里应该使用固定大小的数组。我大意了啊,没有闪,当时移植这份代码的时候就留意到了这个另类写法,当时还特地看了一下实现,但最终还是栽在了这里。 

这段代码是乱打(写)的吗?他可不是乱打(写)的,格式清晰、移植方便、还有各种异常处理,明显有备而来。来、骗,来、偷袭我这经验丰富的老同志。这好吗?这不好,我劝他耗子尾汁。

 

寻根问底

事实上,如果对时间要求不是很高的话,这段代码不会有任何问题,它的基本读取功能是没有任何问题的,只是说它的执行时间很不稳定,有的时候几十微秒就可以执行完毕,有时候可能需要几毫秒时间,还有极端的可能是直接死机(Hardfault)!

那么动态数组是如何实现的,或者说它的本质是什么呢?本质就是使用 malloc 函数申请堆空间(在 rt-thread 中又会调用 rt_malloc),然后在离开函数前使用 free 函数释放堆空间。可以查看汇编确认:

看到这里,你也就知道为什么会出现之前的现象了吧。系统未完全运行前,很少有线程申请堆空间,所以执行时间比较稳定,因为它能快速的找到合适的内存块,一旦系统里所有线程正式工作了,涉及到大量的内存申请与释放,有大量的内存碎片,也就不容易找到合适的内存,这样执行时间也就不稳定了,这对于实时要求高的功能是一个灾难。

所以,如果你的功能不要求实时性的话,使用动态数组是可以的,一旦你的功能要求实时性,那么使用静态数组才是更好的选择(如果使用静态数组,一定要注意使用范围,最好加上断言机制),如果代码是在中断执行,rt-thread 系统中,则必须使用静态数组,否则 rt_malloc 无法正常执行(断言失败)。你防住了吗?

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
CSTCC8M38G53-R0 1 Murata Manufacturing Co Ltd Ceramic Resonator,
暂无数据 查看
TLP291(GB-TP,SE 1 Toshiba America Electronic Components OPTOISOLATOR 3.75KV TRANS 4-SO

ECAD模型

下载ECAD模型
$0.1 查看
OPI110C 1 TT Electronics Resistors Transistor Output Optocoupler, 1-Element, 10000V Isolation, ROHS COMPLIANT, PLASTIC PACKAGE-4
$3.62 查看

相关推荐

电子产业图谱

六年开发经验,丰富的KEIL调试经验,STM32使用经验,C语言运用经验。