You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MISRA C 2012指令4.1下库函数忽略指针检查的合规性问询

MISRA C 2012指针检查的实现方案与合规性分析

MISRA C 2012 Directive 4.1要求尽量减少运行时故障,针对指针解引用进一步明确:除非已知指针非NULL,否则解引用前必须检查其是否为NULL。

编写执行简单操作的底层库时,每个函数都做输入指针检查会导致代码体积膨胀,还会降低简单操作的可读性。本文以控制器中计算向量平方欧几里得范数的库为例,给出两种实现方案:


方案1:指针检查实现

库代码

/* file vector.c */

bool_t bVectorNormSq(float32_t pf32Vec[], uint8_t u8Len, float32_t *pf32NormSq)
{
    uint8_t u8n;
    bool bRet = false;

    /* Check pointers */
    if( (pf32Vec != NULL) && (pf32NormSq != NULL) )
    {
        *pf32NormSq = 0.0f;

        for(u8n = 0U; u8n < u8Len; u8n++)
        {
            *pf32NormSq += (pf32Vec[u8n] * pf32Vec[u8n]);
        }
        bRet = true;
    }
    else
    {
        /* Do not alter pf32NormSq (unknown if valid pointer) */
        bRet = false;
    }

    return bRet;
}
/* EOF */

调用方代码

/* file controller.c */

/* ... */

bool_t bControllerStep(void)
{
    float32_t pf32MyVec[3] = { 0 };
    float32_t f32MyNorm = 0.0f;

    /* ... */

         /* MISRA C 2012 Rule 17.7, Call will always be successful, thus return value not checked */
     (void)bVectorNormSq(pf32MyVec, 3U, &f32MyNorm); 
    
         /* ... */

}

/* EOF */

方案2:调用方保证输入有效性,库仅做开发期断言

库代码

/* file vector.c */

/**
 * @note This library assumes that valid pointers will be supplied,
 *       pointers are NOT checked before they are used.
 */

/* Assert macro expands to "(void)(CONDITION)" for NDEBUG defined */
#ifdef NDEBUG
  VECTOR_ASSERT( CONDITION ) (void)(CONDITION)
#else
  /* ... */
#endif /* NDEBUG */

float32_t f32VectorNormSq(float32_t pf32Vec[], uint8_t u8Len)
{
    float32_t f32Norm = 0.0f;
    uint8_t u8n = 0U;

    VECTOR_ASSERT(pf32Vec!=NULL);

    for(u8n = 0U; u8n < u8Len; u8n++)
    {
        f32NormSq += (pf32Vec[u8n] * pf32Vec[u8n]);
    }

}
/* EOF */

调用方代码

/* file controller.c */

/* ... */

bool_t bControllerStep(void)
{
    float32_t pf32MyVec[3] = { 0 };
    float32_t f32MyNorm = 0.0f;

    /* ... */

    f32MyNorm = f32VectorNormSq(pf32MyVec, 3U);

    /* ... */

}

/* EOF */

方案对比与问题引出

方案1中,调用方bControllerStep()能确定传入的数组pf32MyVec是本地栈上定义的,不可能为NULL,因此直接忽略了库函数的返回值。这种场景在库的使用中很常见,会导致调用方频繁忽略返回值,久而久之容易让程序员产生懈怠——哪怕遇到真正需要处理的错误(比如除零),也会习惯性忽略返回值。

方案2则明确假设调用方会提供有效指针,通过注释告知使用者这一前提,仅在开发阶段用断言检查NULL指针,部署时禁用断言。这种设计如果保留布尔返回值,能提醒程序员:库操作的失败可能源于指针无效之外的其他原因(比如除零),使用计算结果前必须谨慎,避免懈怠风险。


技术问题

  1. 在示例场景下,库忽略指针或其他简单输入检查是否符合MISRA C规范?
  2. 除了在源码中记录缺失的输入检查外,是否还需要满足其他条件,比如提交正式偏差申请?

背景说明

本人是航空航天控制方向的学生,希望通过遵循MISRA C等标准编写控制算法,理解实际控制系统的正确编码方式。假设代码运行在故障等级为灾难性(故障会导致人员死亡)的实际系统中。本人了解SAE ARP4754、SAE ARP4761、DO-178C等软硬件工程标准,本次仅关注硬件上执行的指令,不涉及冗余异构硬件、需求、评审、测试等内容。

补充说明:涉事库位于代码栈底层,外部输入(如传感器数据)已做净化处理,希望避免盲目遵循“始终检查所有输入”的规则,陷入盲目模仿编程(Cargo cult programming)的误区。


问题解答

问题1:是否符合MISRA C规范?

符合,但有严格前提:

  • 必须明确证明输入指针不可能为NULL:示例中调用方传入的是栈上数组的地址,本身不可能是NULL,且库处于底层、外部输入已做净化,所有调用场景都能保证输入指针有效。
  • MISRA C 2012 Directive 4.1的核心是“已知指针非NULL时可跳过检查”,只要能通过静态分析、代码评审或设计文档证明指针必然有效,就不违反规范。
  • 开发阶段的断言是合规的补充手段:断言能在调试期捕获意外的无效指针,同时不影响部署后的代码性能和体积,符合MISRA对调试与发布代码的区分要求。

问题2:是否需要提交正式偏差申请?

需要提交偏差申请,原因如下:

  • 尽管场景满足“已知指针非NULL”的前提,但MISRA要求对任何偏离规范的显式行为(包括跳过强制的输入检查)都要记录并申请偏差。
  • 偏差申请中需要明确:
    • 跳过检查的具体场景(如底层库、输入已净化、调用方均为内部模块且能保证指针有效)
    • 验证手段(静态分析报告、代码评审记录、调用方的输入保证机制)
    • 风险控制措施(开发期断言、测试用例覆盖所有调用场景)
  • 对于灾难性故障等级的系统,偏差申请是合规流程的必要环节,能确保所有决策都有可追溯的依据。

内容的提问来源于stack exchange,提问作者VictorS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 23:01:54