无限循环|嵌入式开发:成功进行代码审查的10个问题

无限循环|嵌入式开发:成功进行代码审查的10个问题

文章图片


多年来 , 开发人员在审查代码时有一些常见的问题 , 无论公司的规模有多大 , 开发过程有多成熟 , 总会出现问题 。 为了帮助缓解这些常见问题 , 嵌入式开发人员在审查C代码时可以提出一下10个问题 , 以帮助找到潜在的bug问题 。
问题 1 – 程序构建时没有警告吗?
如果编译不成功 , 就无法在目标上加载代码 。 成功的编译需要程序员努力消除任何语法错误 , 以使编译器满意并创建输出文件 。 但是 , 编译器可以构建一个没有错误的应用程序 , 但仍然会发现其他异常 , 如隐式强制转换 , 并将其报告为警告 。 因此 , 一个真正成功的程序编译不仅应该零错误 , 还应该零警告 。
问题2 – 有任何阻塞功能吗?
微控制器(MCU)的主要目的之一是能够处理实时事件 。 MCU应该能够以一种非常确定的方式处理这些事件 , 这种方式可以被测量和证明 。 然而一个常见错误是 , 一个驱动程序或一些应用程序代码段被编写为进入一个循环或调用一个延迟函数很长一段时间 。 但是 , 循环或延迟会阻止任何其他代码在处理器上运行 , 这可能会损害确定性 。
问题3 – 是否存在潜在的无限循环?
哪个嵌入式开发人员会故意将无限循环放入他们的代码中?(当然不包括那些在任务或应用程序的主循环中需要的代码) 。 然而 , 网络上和芯片供应商提供的许多示例代码都表现出无限循环故障行为 。 例如 , 将数据写入闪存或 EEPROM 的代码通常会监控硬件标志是否完成 。 示例代码将在标志上创建一个 while 循环 , 以在继续之前达到某个状态 。 但是如果硬件出现故障并且标志永远不会被设置 , 代码就会陷入无限循环!
可以补救这种无限循环故障的一种方法是让循环监视系统滴答声或限制循环在最终确定发生错误之前可以执行的次数 。 这些补救措施允许在硬件发生故障时将错误处理内置到系统中 。 尽管普遍认为 , 硬件(和软件)确实失败了 。

问题 4 – 这个函数参数应该是const吗?
程序员往往不会尽可能多地使用const , 尤其是在涉及函数参数时 。 将传递的函数参数声明为const是防止该变量在函数中被意外修改的好方法 。 为什么让未来的嵌入式开发人员意识到他们不应该修改该系统关键变量而应该只使用它呢?
问题 5 – 代码的圈复杂度是否小于10?
监控函数的圈复杂度度量是帮助限制函数变得复杂的好方法 。 该指标直接关系到需要在函数上执行以测试每个分支的最小测试用例数量 。 不仅如此 , 该指标还真正说明了开发人员在编写或修改函数时需要记住多少 。 由于大多数人一次只能跟踪7到9件事 , 因此将圈复杂度保持在10以下是有助于降低错误率的好选择 。
问题 6 – extern 是否受限于静态的自由使用?
C 语言默认变量的作用域为extern , 这个默认值是隐式的 , 在模块中声明的不使用静态变量的变量前面有一个不可见的大外部变量 。 摆脱那个不可见的外部的唯一方法是在声明前面放置一个可见的静态 。 这种做法的另一个好处是使变量在范围内成为局部变量 , 有助于数据隐藏和封装 。 寻找隐式外部变量最常见的地方是模块级变量声明 。
问题 7 – 是否所有 if ... else if ... 条件都以 else 结尾?
在 switch 语句中使用默认情况应该是强制性的 。 如果不存在默认情况 , 静态分析工具会报错 。 嵌入式开发人员可以很容易地看到 , 如果条件保证在各种情况下使用 switch 语句 , 则可能会有一个意外或被忽略的情况 , 应该有一个默认的 end-all 情况 。 这也适用于 if ... else if ... 条件 。 如果要检查两个或多个条件 , 如果这些情况都不符合当前条件怎么办?语句中的最后一个 else 就像 switch 语句中的默认情况一样 。
问题 8 – 是否存在断言和/或输入/输出检查?
嵌入式软件开发人员应该在他们的代码中添加断言 , 以验证他们对程序在某些点的行为的假设是否正确 , 应对入站和出站数据执行边界检查 。 还记得那句老话“垃圾进 , 垃圾出”吗?

问题 9 – 是否有标题保护在场?
标题保护是一个简单的宏 , 可确保标题文件在翻译单元中不包含多次 。 保护是防止双重包含 #include 指令 。 不包括标题保护可能会导致一些非常奇怪的静态分析行为 , 更重要的是 , 嵌入式开发人员使用保护可以防止多个定义错误 。