在普通C程序中,递归本身符合C语言语法,但在MISRA C项目中,是否能用不能只看编译器是否接受。递归会让最大调用深度、栈空间和执行时间更难确定,因此在安全相关和高可靠嵌入式软件中受到严格限制。处理“MISRA C允许使用递归函数吗,MISRA C递归调用违反哪些规则”时,应先明确Rule 17.2的要求,再区分直接递归、间接递归以及正式偏离三种情况。
一、MISRA C允许使用递归函数吗
MISRA C:2023中,Rule 17.2要求函数不能直接或间接调用自身。Perforce QAC的MISRA C:2023规则表将其归类为Required,同时标记为Undecidable。
1、直接递归属于明确违规
函数在自身执行过程中再次调用自己,就是直接递归。
①检查函数体内是否存在对自身的调用。
②即使设置了明确终止条件,只要形成自调用关系,仍然属于Rule 17.2范围。
③即使递归深度理论上只有两三层,也不会因此自动变成合规代码。
例如:
这里的calc直接调用自身,因此终止条件是否明确,并不会改变它属于递归这一事实。
2、Required不等于绝对不能偏离
Rule 17.2属于Required规则。MISRA官方对规则分类的要求是:Required规则应当遵守,如果项目确实不能满足,需要建立正式Deviation并给出相应依据。
①先评估是否可以改成【循环】、【状态机】或显式数据结构。
②确实需要保留递归时,确定【最大递归深度】。
③根据目标平台评估【最坏栈占用】和【最坏执行时间】。
④在偏离记录中说明原因、风险、验证依据和审批结果。
因此,“MISRA C允许递归”更准确的理解是:正常合规代码不应使用递归;确有工程必要时,可以按照Required规则要求执行正式偏离,而不是直接忽略告警。
二、MISRA C递归调用违反哪些规则
就递归这一行为本身而言,MISRA C:2023直接对应的核心规则就是Rule 17.2,并不是出现递归后固定违反多条MISRA规则。其他告警要看具体实现是否同时存在其他独立问题。
1、间接递归同样违反Rule 17.2
间接递归没有明显的“函数调用自己”,因此更容易在代码审查时被忽略。例如:
functionA调用functionB,而functionB又回到functionA,已经形成完整的递归调用环。
①查看静态分析工具生成的Call Graph。
②如果调用路径最终重新返回起始函数,按【间接递归】处理。
③调用链跨多个源文件时,也要继续检查完整路径,不能只分析单个模块。
④A→B→C→A这类多层调用,与A→B→A一样属于Rule 17.2限制范围。该规则明确同时覆盖直接和间接自调用。
2、函数指针和回调需要重点检查
通过函数指针、回调表或状态处理函数调用时,实际目标可能无法仅从单个函数体确定,因此调用环会更加隐蔽。Rule 17.2被列为Undecidable,也意味着完整判断可能需要结合程序调用关系进行分析。
①检查函数指针可能绑定的【全部目标函数】。
②检查回调函数内部是否重新进入注册它的上层函数。
③对跨模块回调建立完整【调用图】,确认最终不会重新回到起点。
④静态分析无法确定动态调用目标时,通过人工代码审查补充判断。
需要注意,递归函数里如果还存在其他MISRA违规,例如参数、指针或控制流问题,应分别按照对应规则处理,不能把所有告警都归到Rule 17.2下面。
三、已有递归代码怎么进行MISRA整改
遗留项目发现递归后,优先目标是消除调用环,同时保持原有算法行为。不同类型的递归适合不同替代方式,不需要机械地把所有函数完全重写。
1、改成可控的迭代结构
①线性递归优先转换成【for循环】或【while循环】,把递归参数变成循环状态。
②树和图遍历需要保存待处理节点时,可以建立固定容量的【显式栈】或【队列】。
③多个状态处理函数相互调用时,可以调整为【状态机】,由主循环决定下一步执行哪个状态。
④修改完成后重新生成【调用图】,确认原来的递归调用环已经消失。
固定容量的数据结构更容易给出最大内存占用,也方便在容量不足时采用明确的异常处理策略。
2、无法替换时准备偏离依据
①给出可以验证的【最大调用深度】,不要只写“递归次数有限”。
②根据实际编译器和目标处理器评估最坏情况下的栈空间需求。
③对最大深度、边界输入以及异常调用路径进行测试。
④将分析结果写入正式Deviation,并按照项目合规流程完成审查和批准。
Required规则出现不符合项时,需要通过正式偏离进行管理,而不是单纯关闭静态分析诊断。
总结
MISRA C限制递归的核心目的,是提高软件资源占用和运行行为的可预测性。递归在C语言中合法,并不代表它自然满足安全编码要求;对于需要严格评估栈空间和实时性的嵌入式项目,这一点尤其重要。实际合规工作中,应把Rule 17.2作为递归问题的主要判断依据,并将确实无法消除的例外纳入可追溯的偏离管理。如需进一步了解MISRA C递归调用规则、Rule 17.2合规判断与递归代码整改,欢迎联系咨询。