嵌入式单片机代码审查是一个非常好的学习过程,可以建立良好的编程习惯,提前发现潜在的bug。

        代码审查是一个系统性的过程,通常会从功能正确性代码规范性性能安全性可维护性等多个维度进行。


一、 功能与逻辑审查 (Functionality & Logic)

这是最基础也是最重要的一步,确保代码做了它应该做的事情。

  • 需求匹配
    • 代码是否完全实现了所有的功能需求?有没有遗漏或多余的功能?
    • 每个功能点是否都有对应的代码实现?
  • 逻辑正确性
    • 条件判断if-else, switch-case 等逻辑是否正确?边界条件是否考虑周全?
    • 循环逻辑for, while 循环的起始条件、终止条件和步长是否正确?是否存在无限循环的风险?
    • 状态机:如果使用了状态机,状态定义是否清晰?状态之间的转换条件是否正确?是否有未处理的状态或非法的状态转换?
    • 变量初始化:所有变量(尤其是全局变量、静态变量)在使用前是否都进行了正确的初始化?
  • 硬件交互正确性
    • 寄存器操作:对单片机寄存器的读写操作是否正确?地址是否正确?位操作是否正确(例如,|= 置位,&=~ 清零)?
    • 时序要求:对于I2C, SPI, UART等外设,代码是否满足其严格的时序要求?是否有必要的延时?
    • 中断处理:中断服务程序(ISR)的逻辑是否正确?是否正确地清除了中断标志位?

二、 代码规范与风格审查 (Code Style & Standards)

规范的代码风格能极大提高可读性和可维护性。

  • 命名规范
    • 变量名/函数名:是否使用了有意义的名称?变量名应遵循 camelCasesnake_case
    • 宏定义:是否全部大写?例如 #define MAX_BUFFER_SIZE 1024
    • 常量:是否使用 const 关键字定义常量,而不是魔法数字(Magic Numbers)?
  • 代码格式
    • 缩进:是否统一使用空格或制表符进行缩进?缩进级别是否一致?
    • 括号if, for, while 等语句的大括号 {} 是否成对出现且位置统一?
    • 空行:在逻辑块之间(如函数之间、if-else 之间)是否使用空行分隔,使代码结构更清晰?
  • 注释
    • 函数头注释:每个函数(尤其是对外提供的API)是否有注释,说明其功能、参数和返回值?
    • 复杂逻辑注释:对于复杂的算法、难以理解的逻辑或临时的解决方案(workaround),是否有注释说明原因和思路?
    • TODO注释:是否有未完成的功能或需要优化的地方,并使用 // TODO: 进行了标记?

三、 性能与效率审查 (Performance & Efficiency)

嵌入式系统资源有限(CPU、RAM、Flash),性能至关重要。

  • 算法与数据结构
    • 是否使用了高效的算法?例如,在查找大量数据时,是否使用了数组而不是链表?
    • 数据结构的选择是否合适?例如,对于需要频繁插入删除的场景,链表是否比数组更合适?
  • 代码执行效率
    • 循环优化:循环内部是否有不必要的计算或函数调用?能否将其移到循环外部?
    • 冗余代码:是否存在重复的代码块?能否将其封装成一个函数?
    • 函数调用开销:在对执行时间要求极高的代码段(如中断服务程序),是否避免了不必要的函数调用?
  • 内存使用
    • RAM消耗
      • 全局变量和静态变量是否过多?能否改为局部变量?
      • 大数组的定义是否合理?在RTOS中,是否考虑了栈的大小?
    • Flash消耗
      • 代码是否过于冗长?是否有优化空间?
      • printf 等函数会占用大量Flash,是否有必要使用?能否用更轻量级的替代方案?

四、 健壮性与安全性审查 (Robustness & Safety)

这部分关注代码在异常情况下的表现。

  • 错误处理
    • 对于可能失败的操作(如内存分配 malloc、文件读写、外设初始化),是否检查了返回值并做了相应的错误处理?
    • 是否有完善的 assert() 宏来捕获程序运行时的逻辑错误?
  • 边界条件处理
    • 对于数组、缓冲区等,是否防止了数组越界访问?
    • 对于输入参数,是否检查了其有效性(例如,检查指针是否为 NULL)?
  • 并发与中断安全
    • 共享资源保护:多个任务或中断是否会访问同一个全局变量或硬件资源?如果是,是否使用了临界区rt_enter_critical/rt_exit_critical)、互斥量(Mutex)等机制进行保护,以防止数据竞争(Race Condition)?
    • 中断服务程序(ISR)规则
      • ISR是否“快进快出”?
      • ISR中是否调用了可能导致阻塞的RTOS API(如 rt_thread_mdelay, rt_sem_take)?这是绝对禁止的。
      • ISR与任务之间的通信是否使用了正确的方式(如 rt_sem_release_from_isr)?

五、 可维护性与可测试性审查 (Maintainability & Testability)

好的代码不仅要能工作,还要易于维护和测试。

  • 模块化与封装
    • 代码是否被合理地划分为多个函数和文件?每个模块的职责是否单一清晰?
    • 是否遵循了“高内聚,低耦合”的原则?一个函数或模块内部联系紧密,而与其他模块的交互尽量少。
  • 可读性
    • 除了注释,代码本身是否易于理解?复杂的逻辑是否被拆分成了多个简单的步骤?
  • 可测试性
    • 函数是否设计得易于单元测试?例如,函数是否只依赖于输入参数,而不是全局状态?

建议:

  1. 从你最熟悉的部分入手:先审查你自己写的代码,或者你负责的模块。
  2. 从基础规范开始:先关注命名、格式、注释这些最直观的部分。这能让你快速感受到代码审查的好处。
  3. 关注逻辑和硬件交互:确保功能正确是第一位的。仔细检查状态机、中断处理和寄存器操作。
  4. 向有经验的同事学习:参与团队的代码审查会议,看看别人是如何发现问题的。

        代码审查是一个持续学习和改进的过程。不要害怕提出问题或被指出问题,每一次审查都是一次宝贵的学习机会。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐