【问题标题】:MISRA 2012 violation - Type mismatch (Rules 10.1, 10.4)MISRA 2012 违规 - 类型不匹配(规则 10.1、10.4)
【发布时间】:2018-11-17 02:03:31
【问题描述】:

我正面临着我无法理解的 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 ints 应该没有问题。 (PC-Lint 通过了第一个 OR 操作并抱怨第二个!

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

尽管所有操作数都声明为uint8_t,但我不明白为什么存在这些违规行为?

我尝试在每两个 ORed 常量周围加上括号。我还尝试将它们全部转换为uint8_tvolatile uint8_t。未解决违规问题。

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

【问题讨论】:

  • 不是你的问题,而是:你为什么写(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR?没有括号的I2C_CCRH_FS | I2C_CCRH_DUTY | I2C_CCRH_CCR会不会有什么问题?
  • 如果解决方案是添加额外的演员,就像在接受的答案中一样(这让我觉得这是一个经典的例子,为了安抚风格指南而制作代码 worse,但是那是另一个问题),在我看来,最好消除原始位掩码定义中的强制转换。为什么不直接说#define I2C_CCRH_FS 0x80 之类的? (或者#define I2C_CCRH_FS 0x80u,如果强调它们是未签名的很重要?)这样你也不需要在表达式中进行任何强制转换。 MISRA 会很高兴,那些(正确地)不赞成明确演员表的人也会很高兴。
  • 这段代码是我在项目中使用的一个大库(stm库)的sn-p,因此很难更改变量的定义。当我在做一个与安全相关的项目时,我必须对照 MISRA 检查这个库。我接受的答案刚刚解决了这个问题。我认为没有更好的解决方案。是的,我有一行代码,其中 10 个操作数之间存在 ORing。因此,将每个结果转换为uint8_t 会使代码更难阅读并且更容易出错。所以我决定只禁用此特定行的错误消息。你有更好的解决方案吗?
  • 这最终成为一个难以思考的问题,恐怕我无法为您提供建议。您的首要目标是 (a) 使代码安全,(b) 使代码可读,(c) 满足 MISRA,还是 (d) 避免需要大量审查和批准以致成本过高的大规模更改? (不幸的是,目标(a)、(b)和(c)并不总是一致的。)如果是我,我会毫不犹豫地删除定义中的演员表——但这只是我,我不能充分权衡我的选择与目标 (c) 和 (d),因为这些目标从未应用于我的工作。
  • @SteveSummit 我会做所有的 a、b、c 和 d,看看我的答案 :) 删除演员表并使用 u 后缀让 MISRA 很开心,代码也很安全。

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


【解决方案1】:

当您执行按位运算(I2C_CCRH_FS | I2C_CCRH_DUTY) 时,结果将提升为整数。见整数提升规则Here

因此,上述操作的结果与下一个按位或| I2C_CCRH_CCR之间发生了不匹配@

要解决此问题,您需要向 BOTH Bitwise 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

【讨论】:

  • 它仍然不符合 MISRA,因为 ~ 的结果是 int,不应将其分配给 uint8_t 类型。不同的基本类型类别,因此它违反了 10.3。不错的链接:)
【解决方案2】:

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;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 后缀。

【讨论】:

  • 感谢您提供的信息丰富的回答。整数提升规则迫使我们在按位运算中将大部分 unsigned char 转换为 unsigned int 以保持 MISRA 兼容,对吗?您能否解释一下为什么~ 的结果总是signed int?即使操作数是unsinged int?
  • @SalahuddinAhmed 是的,大多数时候将小整数类型转换为无符号整数是个好主意。如果 ~ 的操作数是任何有符号的小整数类型,则 ~ 的结果是有符号整数,因为整数提升。在 unsigned int 的情况下,没有提升。见Implicit type promotion rules
  • 实际上,您应该使用 U,而不是 u (MISRA C:2012, 7.3)。
  • @Matthias No. 相关规则为 MISRA-C:2012 7.2。 “应应用‘u’或‘U’后缀……”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多