0

我已经接管了其中包含许多复合赋值运算符的代码。我认为复合运算符并不“真正”符合 MISRA。我似乎找不到对他们的任何参考。

我相信我了解正在发生的事情,并且实际上应该将其分开。

UINT16 A |= B; /* Incorrect */
UINT16 A = (UINT16)((UINT32)A | (UINT32)B); /* Correct */
UINT16 A <<= 1u; /* Incorrect */
UINT16 A = (UINT16)((UINT32)A << (UINT32)1u); /* Correct */

所以,我的问题是:

  1. MISRA 不赞成复合作业吗?
  2. 有什么快速解决方法,而不是忽略警告?

谢谢,

4

1 回答 1

1

MISRA 不赞成复合作业吗?

不是这样的。复合赋值的规则类似于简单赋值的规则。MISRA 在一般情况下谈到赋值运算符,包括所有这些运算符。

然而,MISRA 不赞成隐式类型提升,请参阅隐式类型提升规则。除非您了解隐含促销,否则您无法理解这些 MISRA 警告。

有什么快速解决方法,而不是忽略警告?

如果不了解警告,您将无法真正解决此问题。唯一的快速解决方法是只uint32_t在任何地方使用,从不使用有符号或小整数类型,但这并不总是可行的。如果所有变量都是uint32_t.

一般来说,最新的 MISRA 只允许同一基本类型类别的类型之间进行各种转换。无符号整数是这样的一类,有符号整数是另一类,依此类推。

在不知道 and 的类型的情况下,很难判断您的代码究竟是如何违反 MISRABsizeof(int)。这与复合赋值本身没有任何关系,除了复合赋值运算符在涉及隐式提升时使用起来有点麻烦。

MISRA 不赞成将表达式的值(在隐式提升之后)分配给同一类别的更窄的基本类型或不同的类别。用简单的英语来说,例如,您不应该将uint32_t操作的结果分配给uint16_t变量,或者将有符号的结果分配给无符号的变量。这通常通过在适当的位置进行铸造来解决。


关于您的具体示例,假设 B 是uint16_t并且 CPU 是 32 位,那么您会遇到隐式类型提升的问题。

由于A |= B等价于,因此在 32 位 CPU 的情况下,A | B通常的算术转换会将操作数提升为。int所以它是有符号的 32 位类型。

假设您有A << 31u- 那么这实际上会调用一个未定义的行为错误,该规则试图防止该错误。

MISRA-C 合规性的充分修复:

A = (uint16_t) (A | B); // compliant
A = (uint16_t) ((uint32_t)A << 1u) // compliant
于 2020-08-12T10:33:05.237 回答