我得到MISRA C-2012规则10.3违规:隐含转换" var4 + var5"从基本类型签名的32位int到不同或更窄的基本类型无符号8位int"以下代码。
int8_t var4 = -10;
uint8_t var5 = 15;
uint8_t var6 = var4 + var5;
" var4 + var5"被解释为32位int,因为每个都是8位大小。
还有解决这个问题的正确方法是什么?
答案 0 :(得分:3)
由于整数促销,会发生这种情况。详情见C standard
的第6.3.1.1节2 以下内容可用于任何可能使用
int
或unsigned int
的表达式:
- 具有整数类型(
int
或unsigned int
除外)的对象或表达式,其整数转换等级小于或等于 排名为in
t和unsigned int
。- 类型为
_Bool
,int
,signed int
或unsigned int
的位字段。如果
int
可以表示原始类型的所有值(限制为 通过宽度,对于位字段),该值被转换为int
; 否则,它将转换为unsigned int
。这些被称为 整数促销。所有其他类型的整数不变 促销。
由于int8_t
和uint8_t
的排名低于int
,因此在表达式中使用时,这些类型的变量会提升为int
。在以下情况下:
uint8_t var6 = var4 + var5;
var4
和var5
都提升为int
,+
运算符的结果也是int
类型。然后将该值分配回var6
,这是uint8_t
,这可能会导致值被截断。
处理此问题的最佳方法是首先验证结果是否无法溢出,然后显式转换结果:
uint8_t var6 = (uint8_t)(var4 + var5);
答案 1 :(得分:2)
原因是implicit type promotions。在该单行中有3个隐含的促销,这是危险和草率的风格。在一行代码中,您有整数提升/通常算术转换和隐式左值转换。
您必须了解这些封面如何在C中工作,以便编写无错误的C代码,但您还必须了解它们才能使用MISRA-C。事实上,MISRA-C的目的之一就是教育程序员关于隐式类型的促销 - 您还可以在MISRA-C文档中找到解释。
您的代码实际上违反了几项MISRA-C:2012规则。不仅10.3关注隐式左值转换,而且还关注10.4:
执行常规算术转换的运算符的两个操作数应具有相同的基本类型类别。
var4
基本上已签名,var5
基本上未签名。因此,仅将结果转换为适当的类型是不够的。要获得符合MISRA-C的代码,必须将两个操作数转换为相同的类型。或者更好的是,使用适当类型的变量开头:将-10 + 15
的结果存储在无符号变量中没有多大意义。要么你需要签名号码,要么你不需要。
要获得完全可移植的MISRA-C兼容代码,这应该是一种无法隐式提升的类型,例如uint32_t
。
uint8_t var6 = (uint8_t) ((uint32_t)var4 + (uint32_t)var5);
替代地
int8_t var6 = (int8_t) ((int32_t)var4 + (int32_t)var5);
这个表达式是粗犷的,专业的C,因为它不包含单个隐式促销。它是自我记录的代码,因为它表明程序员知道并考虑了隐式类型的促销。与只有8位操作数的表达式相比,不会影响性能,因为程序员可以自由优化。