MISRA C ++规则:5_0_3
尝试使用一种符合MISRA的静态工具分析器,无法解决它。
#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
uint32_t num = 0U;
bool Flag =false;
num |= (Flag ? (0b10 << 10):(0b00 << 10));
}
请帮助解决此问题。 错误消息是: 1.此二进制按位运算符的非常数操作数具有不同的基本类型。 2.这个复杂的表达式被隐式转换为另一个基本类型。
答案 0 :(得分:1)
首先,0b
语法是非标准的,因此无法确定它将做什么。仅该语法就违反了MISRA;我建议改用十六进制常量。无论如何,您的代码不应包含任何“魔术数字”。
如果我们假设您的编译器将非标准0b
整数常量视为常规十进制整数常量,则其类型为(带符号)int
。您的操作结果是带符号的int,即MISRA称之为“基本上带符号”。但是,您将其存储在uin32_t
中,该变量实际上是未签名的,这是MISRA违规行为和错误的原因。
请注意,移位运算符始终具有提升的左操作数整数的类型。因此,编写类似0b10 << 10u
的内容将无济于事。根据经验,从不在带符号的操作数上不使用按位运算符。
还要注意,?:
是特殊的,因为它包含第二和第三操作数的隐式转换-它们被平衡为相同的类型(根据“通常的算术转换”)。这会产生一些细微的错误,因此,在使用小整数类型或带符号类型(或在使用MISRA的情况下)时,最好不要使用?:
。
我还建议将代码重写为“魔术数字”较少的内容:
#define MASK_SOMETHING (0x2u << 10) // give this some meaningful name
#define MASK_EMPTY (0x0u << 10) // give this some meaningful name
uint32_t num = 0U;
bool Flag = false;
...
if(Flag)
{
num |= MASK_SOMETHING;
}
显然,对零进行按位或运算不是很有意义,如果没有设置标志,您可能打算清除位?在这种情况下,您需要else { num &= ~MASK_EMPTY; }
。
(也可以进一步优化以摆脱分支。)