我有下面的函数来检查一些计数值和更新最终计数。
uint16 final_count = 0U;
uint8 count1 = 0U;
uint8 count2 = 0U;
uint8 count3 = 0U;
uint8 count4 = 0U;
void test(void)
{
uint8 input = 0U;
input = get_input(); //Input
count1 = get_count1(); //count1
count2 = get_count2(); //count2
count3 = get_count3(); //count3
count4 = get_count4(); //count4
if(input == 1U)
{
final_count= count1 + count2; // Both warnings Here
}
else if(input == 2U)
{
final_count= count2 + count3; // Both warnings Here
}
else
{
final_count= count1 + count2 + count3 + count4; // Both warnings Here
}
}
在MISRA检查期间,我在if else中得到以下错误
A composite expression of 'essentially unsigned' type (unsigned char) is being converted to wider unsigned type, 'unsigned short' on assignment.
Integral promotion : unsigned char promoted to signed int.
我试过用下面的方法解决
final_count = (uint16)(count1 + count2);
final_count = (uint16)(count3 + count4);
final_count = (uint16)(count1 + count2 + count3 + count4);
但是这并不能解决MISRA警告。这里到底发生了什么问题?有没有什么建议可以不用临时变量来解决这些警告?
2条答案
按热度按时间ubof19bj1#
在你的例子中,
count1 + count2
是一个复合表达式。操作数是uint8_t
,因此本质上是无符号的。你把它赋给了一个更宽的无符号类型uint16_t
,因此代码违反了规则10.6。MISRA为规则10.6中的“复合表达式”提供了两个理由:
int
。uint16_t
中,那么加法也是使用uint16_t
执行的,这当然是错误的。(MISRA似乎坚持认为这是一个常见的误解,但我并不真正相信...)此外,规则10.8规定,不允许将复合表达式的结果强制转换为更广泛的基本类型(
(uint16_t)
强制转换版本)。这里的目的是防止隐藏的意外,如溢出和环绕。例如,在您的特定情况下,不清楚您是否期望8位环绕。如果你期望结果的值大于255,那么你可以在255附近找到一个值。没有人(包括你自己)可以通过观察未注解的代码来判断。所以强制转换结果也不会起作用。解决方案是在执行加法之前将变量强制转换为预期的类型:
顺便说一句,请养成使用标准C类型
uint8_t
的习惯,而不是一些私人车库的非标准uint8
/u8
/byte
......好的工程=遵循标准和最佳实践。坏的工程=只是为了让事情变得复杂。7vux5j2d2#
在您的示例中,您声明(使用我的注解):
你的三个任务是:
这违反了MISRA C:2012 R.10.6和R.10.8
然后你会问:
这里发生的确切问题是什么?有什么解决这些警告的建议吗
在MISRA C:2012的s8.10.3和附录C中可以找到解释-您已经阅读了这本书,不是吗,并且不仅仅依赖于工具的输出?
这里的问题是一个(非常常见的)误解了C所展示的奇怪(但定义良好)的整数提升行为,特别是当使用小于
int
的unsigned int
egers时(当您可能不期望时,它会提升为signed int
)-正如错误2所强调的那样。还存在四个
uint8
可能溢出的真实的风险。添加强制转换可以解决R.10.6的问题,但不能解决R.10.8的问题。
在您的示例中,最简单的解决方案是将四个
count
n 变量声明为uint16
,然后所有计算都在uint16
中执行,而赋值不会是 * 复合表达式 *,因此隐式转换是可以的。(see MISRA附属机构的简介)