空指针问题

Null pointer issue

我面临 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 违规吗?

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

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

根据 1999 C 标准,第 6.3.2 节 "Pointers",第 3 段

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

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

这意味着

tm_uint8* diagBuf = 0u;

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

还有以下说法

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

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

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

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

C11 6.3.2.3 状态:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant

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

如果按照简单赋值C11 6.5.16.1的规则,就不存在=左操作数是指针,右操作数是算术类型的情况。这个规则在标准中很明确,像int* ptr = 1234;这样的代码就是简单的无效C,一直都是无效的C(是标准的"constraint violation")。没有 warning/error 就让它通过的编译器是垃圾,不符合标准。

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

  • the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant

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

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

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

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

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


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

  • 指向硬件地址时不使用 volatile 总是一个错误。
  • 使用 diagBuf[0] + 0x40u 将某位设置为 1 是一种糟糕的方法。如果该位已经设置,则会出现严重错误。请改用 |
  • 假设 diagBuf 是指向字节的指针,那么 diagBuf[0] = diagBuf[0] + 0x40u; 是 MISRA-C:2012 违反规则 10.3,因为您分配了更宽的类型 ("essentially unsigned") 到更窄的类型。符合 MISRA 的代码是:

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