使用按位运算符的Misra违例

m47*_*47h 4 c misra

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

UartPtr->C &= ((uint8_t)(~SIO_C2_SBK));
Run Code Online (Sandbox Code Playgroud)

#define SIO_C2_SBK ((uint8_t)0x01u)
Run Code Online (Sandbox Code Playgroud)

并被UartPtr定义为

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

与基础数据结构:

typedef volatile struct UartStructTag
{
  uint8_t      BDH;
  uint8_t      BDL;
  uint8_t      C1;
  uint8_t      C2;
} UartStruct;
Run Code Online (Sandbox Code Playgroud)

我的Misra检查员抱怨第一行,并说明

具有负值的整数常量表达式将转换为无符号类型.

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

UartPtr->C |= ((uint8_t)(SIO_C2_SBK));
Run Code Online (Sandbox Code Playgroud)

所以问题来自于逐位否定.但由于所有操作都直接转换为uint8_t,因此我不会违反MISRA标准.谁想帮助我呢?

fuz*_*fuz 6

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

UartPtr->C &= ((uint8_t)(~(int)(uint8_t)0x01u));
Run Code Online (Sandbox Code Playgroud)

这只是

UartPtr->C &= ((uint8_t)(~1));
Run Code Online (Sandbox Code Playgroud)

哪里~1-2两个补码架构的价值.

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

UartPtr->C &= ((uint8_t)(~(unsigned)SIO_C2_SBK));
Run Code Online (Sandbox Code Playgroud)

  • @m47h 该规则是试图保护您免受诸如“if(~SIO_C2_SBK > 0)”之类的情况的影响,这种情况不会按预期运行。这是一个非常令人讨厌的错误。 (2认同)

Lun*_*din 5

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

#define SIO_C2_SBK ((uint8_t)0x01u)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 如果您不需要这个宏来给出uint8_t,那么只需删除(uint8_t强制转换即可解决问题。

  • 如果由于某种原因该宏必须给出uint8_t,则将代码更改为以下内容(符合 MISRA 要求):

    UartPtr->C &= (uint8_t) ~(uint32_t)SIO_C2_SBK;
    
    Run Code Online (Sandbox Code Playgroud)

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