我能做些什么来避免 MISRA 对下面的代码给出这个错误?我尝试使用(unit16_t)进行投射。但是它不允许显式转换。
复杂表达式中从基础 MISRA 类型“unsigned char”到“unsigned int”的非法隐式转换(MISRA C 2004 规则 10.1)
uint8_t 速率 = 3U; uint8_t 百分比 = 130U; uint16_t basic_units = 比率 * 百分比;
问题是比率和百分比都被整数提升默默地提升为类型“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;否则,它将转换为无符号整数。这些被称为整数促销。
来自 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.
为了防止这种情况,您必须显式地进行类型转换。在考虑了更多之后,我会选择上面两行的第一行。
对于乘法,在乘法之前执行隐式转换。也许在乘法关闭您的工具之前进行显式转换
uint16_t basic_units = (unsigned)rate * (unsigned)percentage;
结果unsigned
值应该被隐式转换为uint16_t
没有警告。如果您的工具也选择成为 PITA,请尝试另一个显式转换:
uint16_t basic_units = (uint16_t)((unsigned)rate * (unsigned)percentage);
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 规则试图使代码更安全,而与目标平台上类型的大小无关。
如果您尝试使用 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);