空指针问题
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;);
我面临 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;);