问题描述
我已经接管了其中包含许多复合赋值运算符的代码。 我认为复合运算符不符合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 */
所以,我的问题是:
谢谢
解决方法
MISRA是否不满意复合作业?
并非如此。复合分配的规则类似于简单分配的规则。 MISRA在一般情况下谈到赋值运算符,包括所有这些。
但是,MISRA并不赞成隐式类型提升,请参见Implicit type promotion rules。除非您了解隐式促销,否则您将无法理解这些MISRA警告。
有什么快速解决方案,而不是忽略警告吗?
如果不了解警告,就无法真正解决此问题。唯一的快速解决方案是仅在任何地方都使用uint32_t
,并且永远不要使用有符号或小的整数类型,但这并不总是可行的。如果所有变量均为uint32_t
,则您的原始代码将符合要求。
通常,最新的MISRA仅允许在同一基本类型类别的类型之间进行各种转换。无符号整数就是这样一个类别,带符号整数属于另一类,等等。
在不知道B
和sizeof(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