我可以做些什么来避免MISRA为下面的代码提供此错误?我尝试使用(unit16_t)进行投射。但后来它没有允许明确的转换。
复杂表达式中从基础MISRA类型“unsigned char”到“unsigned int”的非法隐式转换(MISRA C 2004规则10.1)
uint8_t rate = 3U; uint8_t percentage = 130U; uint16_t basic_units = rate * percentage;
答案 0 :(得分:5)
问题在于,整数促销会默认促销费率和百分比,以输入“int”。因此,乘法是在带符号的类型上执行的。
MISRA兼容代码是将代码重写为
uint16_t basic_units = (uint16_t)rate * (uint16_t)percentage;
或者按照MISRA的建议,立即将表达式的结果强制转换为“基础类型”:
uint16_t basic_units = (uint8_t)(rate * percentage);
编辑:澄清如下。
ISO 9899:1999 6.3.1.1 2
如果int可以表示原始类型的所有值,则该值将转换为int; 否则,它将转换为unsigned int。这些被称为整数 促销
MISRA-C的资料性文字:
MISRA-C:2004 6.10.3危险类型转换:
/ - /
- 更改算术运算中的签名:整数提升通常会导致两个无符号操作数产生(signed)int 类型的结果。例如,如果 int 为32位,则添加两个16位无符号操作数将产生带符号的32位结果,如果 int 为16,则产生无符号的16位结果位。
我实际上不确定我上面的第二行是否会满足MISRA,第二种想法我可能已经将MISRA 10.1与10.5混淆了,后者强制立即转换为基础类型,但仅限于某些按位运算符。
我使用LDRA静态代码分析对这两行进行了测试,并没有抱怨(但是提供了一些不正确的,不相关的警告),但是LDRA在MISRA-C上的表现也很差。
无论如何,原始问题中的问题是速率和百分比都被整数提升隐式转换为类型为 int 的签名,因为 int 可以代表所有uint8_t的值。所以它变成
uint16_t basic units = (int)rate * (int)percentage.
为了防止这种情况,你必须明确地进行类型转换。在更多地考虑之后,我会选择上面两条线的第一线。
答案 1 :(得分:2)
隐式转换在乘法之前执行,用于乘法。也许在乘法之前进行显式转换会关闭您的工具
uint16_t basic_units = (unsigned)rate * (unsigned)percentage;
生成的unsigned
值应隐式转换为uint16_t
,不会发出警告。如果您的工具也选择成为PITA,请尝试另一种显式转换:
uint16_t basic_units = (uint16_t)((unsigned)rate * (unsigned)percentage);
答案 2 :(得分:1)
MISRA规则试图确保用于计算的“基础类型”与结果类型相同。要实现这一点,您可以转换一个或两个操作数:
uint8_t rate = 3U;
uint8_t percentage = 130U;
uint16_t basic_units = (uint16_t)rate * percentage;
在32位架构上,没有强制转换的结果是正常的,但请考虑以下因素:
uint32_t rate = ...;
uint32_t percentage = ...;
uint64_t basic_units = rate * percentage;
在32位架构上,操作将以32位执行 - 即使目标类型为64位宽。在速率和百分比足够大的情况下,这可能导致操作包装为32位,因此将丢失适合目标类型的数据。
MISRA规则试图使代码更安全,而不管目标平台上类型的大小。
答案 3 :(得分:0)
如果你尝试使用C风格的转换来演示你的操作数,你可能只是给你的工具一些其他的抱怨。所以,而不是这样做:
uint16_t basic_units = (uint16_t)rate * (uint16_t)percentage;
您可能需要这样做:
uint16_t basic_units = static_cast<uint16_t>(rate) * static_cast<uint16_t>(percentage);