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

Sal*_*din 6 c lint misra type-mismatch implicit-conversion

我正面临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);
Run Code Online (Sandbox Code Playgroud)

在之前的代码中,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]
Run Code Online (Sandbox Code Playgroud)

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

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

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

我试过在每两个ORed常量周围加上括号.我也尝试过将它们全部uint8_t投入使用volatile uint8_t.未解决违规行为.

我查了一下这两个职位(1,2),但他们没有回答我的问题.

Lun*_*din 3

I2C_CCRH_FS | I2C_CCRH_DUTY本身符合 MISRA 标准。两个操作数本质上都是无符号的,因此子表达式就可以了。但是,仍然存在每个操作数到 的隐式转换int。实践中的结果是 类型int

在伪代码中:当您这样做时(result as int) | I2C_CCRH_CCR,隐式提升之前的操作数具有类型int | uint8_t。也uint8_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;博士。如何使代码符合 MISRA 标准:

你要么必须做一些像这样的半可怕的事情:

I2C->CCRH &= (uint8_t) ~ (uint8_t) ((uint8_t)(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR)
Run Code Online (Sandbox Code Playgroud)

这有点乱。相反,我会提前施展。假设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
Run Code Online (Sandbox Code Playgroud)

当处理 MCU 寄存器等时,上述风格很有用。该代码是可以接受的,但可以进一步简化。

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

I2C->CCRH &= (uint8_t) ~(I2C_CCRH_FS | I2C_CCRH_DUTY | I2C_CCRH_CCR);
Run Code Online (Sandbox Code Playgroud)

而且它仍然符合 MISRA 标准,因为uMISRA 喜欢方便的小后缀。