按位运算符违反 Misra

Misra violation with bitwise operator

我写了以下 MISRA 不喜欢的代码:

UartPtr->C &= ((uint8_t)(~SIO_C2_SBK));

#define SIO_C2_SBK ((uint8_t)0x01u)

UartPtr 定义为

UartPtr = (UartStruct*) 0x12345678; /* I know that this is also a violation of MISRA */

底层数据结构:

typedef volatile struct UartStructTag
{
  uint8_t      BDH;
  uint8_t      BDL;
  uint8_t      C1;
  uint8_t      C2;
} UartStruct;

我的 Misra 检查器抱怨第一行并指出

An integer constant expression with negative value is being converted to an unsigned type.

但是,以下行不会导致 MISRA 出现问题:

UartPtr->C |= ((uint8_t)(SIO_C2_SBK));

所以问题出在按位取反。但是由于所有操作都直接转换为 uint8_t,因此我没有违反 MISRA 标准。谁想在这里帮助我?

在任何算术表达式中,类型小于 int 的值在处理之前会隐式转换为 int。 C 语言不能对小于 int 的类型进行算术运算。因此,您的代码实际上是这样的:

UartPtr->C &= ((uint8_t)(~(int)(uint8_t)0x01u));

这只是

UartPtr->C &= ((uint8_t)(~1));

其中 ~1 在二进制补码架构上的值为 -2

要解决此问题,请在应用按位非之前转换为 unsigned 或任何其他大于 int 的无符号类型:

UartPtr->C &= ((uint8_t)(~(unsigned)SIO_C2_SBK));

与大多数 C 运算符一样,~ 运算符将在应用运算符之前对操作数进行隐式整数转换。

#define SIO_C2_SBK ((uint8_t)0x01u)

所以上面的宏是问题所在,因为您将文字从 unsigned int 类型强制转换为小整数类型,这将被隐式提升。在应用 ~ 之前,您最终得到 int 而不是 uint8_t

这违反了 MISRA-C:2004 的规则 10.1,该规则不允许产生不同符号类型的隐式转换(这种转换很危险,所以这是一个很好的规则)。

  • 如果您不需要此宏来提供uint8_t,那么只需删除(uint8_t 转换即可解决问题。

  • 如果这个宏出于某种原因必须给出 uint8_t,则将代码更改为(符合 MISRA):

    UartPtr->C &= (uint8_t) ~(uint32_t)SIO_C2_SBK;
    

    其中 uint32_t 对应于给定平台上 int 的大小。