【问题标题】:Null pointer issue空指针问题
【发布时间】:2018-03-14 10:40:28
【问题描述】:

我正面临 MISRA C 2004 违反规则 1.2“可能使用空指针。我正在使用的代码如下:

tm_uint8* diagBuf = 0u;
diagBuf[0] = diagBuf[0] + 0x40u; 
diagBuf[2] = 0x01u;
diagBuf[0] = diagBuf[0] + 0x40u;
diagBuf[2] = 0x01u;

这只是上述代码的一部分。有些语句有“IF”条件。

有人能指出我为什么会违反 MISRA 吗?

【问题讨论】:

  • 显然,您使用的是空指针。 diafBuf 指向地址 0。
  • 最好只是将其发回给开发人员并说“MISRA C 规则 1.2 违反 - 修复它”。
  • @Pras 不使用 malloc 不也是 MISRA 规则吗?
  • @AndrejsCainikovs 空指针一般不会“指向地址 0”
  • “可能使用空指针” - 这让我笑了

标签: c pointers null-pointer misra


【解决方案1】:

根据 1999 C 标准,第 6.3.2 节“指针”,第 3 段

值为 0 的整数常量表达式,或这种类型转换为 void * 的表达式称为空指针常量。如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。

(请注意,我已将上面第一句末尾的交叉引用删除到脚注中,该脚注解释了 NULL<stddef.h> 和其他标题中定义为空指针常量)。

这意味着

tm_uint8* diagBuf = 0u;

使用空指针常量初始化diagBuf,因为0u 是一个值为零的整数常量表达式。因此,diagBuf 被初始化为空指针。

还有以下陈述

diagBuf[0] = diagBuf[0] + 0x40u; 
diagBuf[2] = 0x01u;

两者都取消引用空指针。根据 C 标准,这是未定义的行为。

因此,报告的 Misra 违规行为是完全正确的。

此类代码可接受的情况(例如,可以编写豁免 Misra 规则的理由,并在系统开发环境中获得批准)在实践中非常有限。

【讨论】:

  • 我认为您是对的,因为我向软件开发人员解释了这些问题,然后他也同意您提到的事情。另外,我不明白为什么人们对这个帖子投了反对票。我确实研究过空指针和 MISRA 规则。
【解决方案2】:

你将 0u (so, 0, so NULL) 影响到 diagBuf,然后你将它与 "diagBuf[0]" 一起使用。

要么分配它(malloc),要么更正声明以满足您的需要(tm_uint8 diagBuf[3]; 至少)

【讨论】:

    【解决方案3】:

    C11 6.3.2.3 状态:

    值为 0 的整型常量表达式,或这种类型转换为 void * 的表达式称为 空指针常量

    这是 C 语言中唯一可以将指针分配给值 0 的情况 - 以获取空指针。问题中的行永远不能用于将指针设置为指向地址 0,因为在所有其他情况下,将整数值分配给指针是无效的 C。

    如果我们通过简单赋值C11 6.5.16.1的规则,那么不存在=的左操作数是指针而右操作数是算术类型的情况。这个规则在标准中是很明确的,int* ptr = 1234;这样的代码简直就是无效的C,一直都是无效的C(这是对标准的“违反约束”)。让它通过而没有警告/错误的编译器是垃圾,不符合标准。

    简单赋值列出了一个有效异常 (C11 6.5.16.1):

    • 左边的操作数是一个原子的、合格的或不合格的指针,右边是一个空指针常量

    这是问题中的代码编译的唯一原因。

    现在如果你真的想指向硬件地址 0,你必须这样写:

    volatile uint8_t* ptr = (volatile uint8_t*)0u;
    

    这会强制将整数 0 转换为指向地址 0 的指针。由于右操作数既不是0 也不是零转换为void*,它不是 null指针常量,因此ptr 不是空指针。

    C 标准清晰,MISRA-C 与标准完美兼容。


    与问题无关的错误和问题:

    • 在指向硬件地址时不使用 volatile 始终是一个错误。
    • 使用diagBuf[0] + 0x40u 将位设置为1 是一种不好的方法。如果该位已设置,那么您将遇到一个巨大的错误。请改用|
    • 假设diagBuf 是一个指向字节的指针,那么diagBuf[0] = diagBuf[0] + 0x40u; 是违反规则10.3 的MISRA-C:2012,因为您将更宽的类型(“基本上无符号”)分配给了更窄的类型。符合 MISRA 的代码是:

      diagBuf[0u] = (tm_uint8)(diagBuf[0u] + 0x40u;);
      

    【讨论】:

      猜你喜欢
      • 2018-11-19
      • 1970-01-01
      • 2017-02-07
      • 2015-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-31
      相关资源
      最近更新 更多