使用按位运算符的Misra违例

时间:2015-12-02 10:31:02

标签: c misra

我写了以下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检查员抱怨第一行并说明,

  

正在转换具有负值的整数常量表达式   到无符号类型。

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

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

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

2 个答案:

答案 0 :(得分:6)

在任何算术表达式中,小于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));

答案 1 :(得分:4)

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

#define SIO_C2_SBK ((uint8_t)0x01u)

所以上面的宏是个问题,因为你强迫文字从unsigned int类型下降到一个小的整数类型,这将被隐式提升。在应用uint8_t之前,而不是int,而不是~

这违反了MISRA-C:2004的规则10.1,它不允许隐式转换产生一种不同的签名(这种转换是危险的,因此这是一个非常好的规则)。

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

  • 如果由于某种原因此宏必须提供uint8_t,请将代码更改为此(符合MISRA):

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

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