MISRA 2012违规 - 类型不匹配(规则10.1,10.4)

时间:2018-06-07 08:29:04

标签: c implicit-conversion lint type-mismatch misra

我面临MISRA C 2012违规,我无法理解。以下是代码:

#define I2C_CCRH_FS      ((uint8_t)0x80)
#define I2C_CCRH_DUTY    ((uint8_t)0x40)
#define I2C_CCRH_CCR     ((uint8_t)0x0F)

typedef struct I2C_struct
{
  volatile uint8_t CR1;
  volatile uint8_t CR2;
  volatile uint8_t CCRL;
  volatile uint8_t CCRH;
} I2C_TypeDef;

#define I2C_BaseAddress         0x5210
#define I2C ((I2C_TypeDef *) I2C_BaseAddress)

I2C->CCRH &= ~(uint8_t)((I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR);

在之前的代码中,PC-Lint抱怨说:

Unpermitted operand to operator '|' [MISRA 2012 Rule 10.1, required]

Mismatched essential type categories for binary operand [MISRA 2012 Rule 10.4, required]

规则10.1规定ORing unsigned int应该没有问题。 ( PC-Lint通过第一次OR操作并抱怨第二次操作!!

规则10.4规定操作的操作数应具有相同的基本类型。

虽然所有操作数都声明为uint8_t,但我无法理解为什么存在这些违规行为?

我试过在每两个ORed常量周围加上括号。我还尝试将所有这些广告投放到uint8_tvolatile uint8_t。未解决违规行为。

我查看了这两篇帖子(12),但他们没有回答我的问题。

2 个答案:

答案 0 :(得分:2)

执行按位操作(I2C_CCRH_FS | I2C_CCRH_DUTY)时,结果将提升为整数。请参阅整数提升规则Here

因此,上述操作的结果与下一个按位OR | I2C_CCRH_CCR

之间发生不匹配

要解决此问题,您需要在BOTH按位OR运算的结果中添加强制转换。

首先需要将~运算符的结果从int转换回unsigned

I2C->CCRH &= (uint8_t)~(uint8_t)((uint8_t)(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR);

解释

I2C->CCRH &= (uint8_t)~    // Required to cast result of ~ operator to uint8_t
             (uint8_t)     // Casts the result of the 2nd OR to uint8_t
             ((uint8_t)    // Casts the result of the 1st OR    
              (I2C_CCRH_FS | I2C_CCRH_DUTY)  // 1st OR
              | I2C_CCRH_CCR);      // 2nd OR

答案 1 :(得分:2)

I2C_CCRH_FS | I2C_CCRH_DUTY本身符合MISRA标准。两个操作数基本上都是无符号的,因此子表达式很好。但是,仍然会将每个操作数隐式转换为int。实践中的结果是int类型。

在伪代码中:当您执行(result as int) | I2C_CCRH_CCR时,隐式促销之前的操作数具有类型int | uint8_tuint8_t此处也会将整数提升为int。你有不同签名的操作数。

(我猜这个工具抱怨10.4,因为整数提升是通常的算术转换的一部分,这就是10.4的内容。)

这整个表达在练习中不会引起任何问题,因此警告主要是迂腐的。但是想象一下,如果你完成~(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR)没有演员阵容 - 你最终会得到一个负数,就像0xFFFFFFxx中用2的补码表示的那样。这可能是危险的。

要解决此问题,您有两种选择:

  • 对于每个操作,将结果转换回预期类型。这通常是MISRA-C的精神。
  • 在操作之前将操作数强制转换为大型无符号类型。通常更易读IMO。

另请注意,~运算符不应与带符号的操作数一起使用!这违反了规则10.1。回到uint8_t的演员应该在最后完成。

<强> TL; DR。如何使代码符合MISRA标准:

你要么做得像这样半糟糕的事情:

I2C->CCRH &= (uint8_t) ~ (uint8_t) ((uint8_t)(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR)

这有点乱。我宁愿提前投。假设32位CPU:

I2C->CCRH &= (uint8_t) ~( (uint32_t)I2C_CCRH_FS    |  // comment explaining FS
                          (uint32_t)I2C_CCRH_DUTY) |  // comment explaining DUTY
                          (uint32_t)I2C_CCRH_CCR   ); // comment explaining CCR

上述样式在处理MCU寄存器等时非常有用。这段代码是可以接受的,但可以进一步简化。

如果可以将定义更改为#define I2C_CCRH_FS 0x80u,那么您将获得:

I2C->CCRH &= (uint8_t) ~(I2C_CCRH_FS | I2C_CCRH_DUTY | I2C_CCRH_CCR);

并且它仍然符合MISRA标准,因为MISRA喜欢的后缀很小u