MISRA:复合赋值运算符

MISRA: Compound Assignment operators

我已经接管了其中有很多复合赋值运算符的代码。 我认为复合运算符不符合 'really' 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. 是否有任何快速修复方法,而不是忽略警告?

谢谢,

Does MISRA frown upon compound assignments?

并非如此。复合赋值的规则类似于简单赋值的规则。 MISRA 泛指赋值运算符,包括所有赋值运算符。

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

Is there any kind of quick fix, instead of ignoring the warning?

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

,您的原始代码将是合规的

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

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

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


关于你的具体例子,假设 B 是 uint16_t 而 CPU 是 32 位,你会遇到隐式类型提升的问题。

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

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

MISRA-C 合规性的足够修复:

A = (uint16_t) (A | B); // compliant
A = (uint16_t) ((uint32_t)A << 1u) // compliant