为什么我的工具在这里抛出MISRA错误?

我该怎么做才能避免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;

问题是,整数提升会默默地提升速率和百分比,以输入“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. 

为了防止这种情况,你必须明确地进行类型转换。 在考虑之后,我会选择上面两条线的第一线。

对于乘法,在乘法之前执行隐式转换。 也许在乘法之前进行显式转换会关闭您的工具

 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(rate) * static_cast(percentage);