在一个针对16位处理器的程序中有一个巨大的宏,下面的代码(简化)出现了几次:
typedef unsigned short int uint16_t;
uint16_t var;
var = ~0xFFFF;
MISRA抱怨警告12.4:整数转换导致截断。用于获得此功能的工具是Coverity。
我已经检查了论坛,但我确实需要一个解决方案(而不是用实际值来改变否定),因为这条线位于具有不同参数的宏内。
我尝试了很多东西,这里最后的尝试也失败了:
var = (uint16_t)((~(uint16_t)(0xFFFFu))&(uint16_t)0xFFFFu);
(值0xFFFF只是一个例子。在实际代码中,值是一个可以取任何值(但是16位)的变量)
请问您有其他想法吗?感谢。
编辑:
我已尝试使用32位值,结果与以下代码相同:
typedef unsigned int uint32_t;
uint32_t var;
var = (uint32_t)(~(uint32_t)(0xFFFF0000u));
答案 0 :(得分:2)
要点:
假设您使用静态分析仪进行MISRA-C:2012,您应该收到违反规则10.3和7.2的警告。
规则12.4仅涉及无符号整数常量的环绕,这只能与二进制+和 - 运算符一起发生。这似乎无关紧要。
对于MISRA-C:2004 12.4和MISRA-C:2012 12.4,警告文本似乎都没有意义。可能是该工具显示错误的警告。
然而,有一条MISRA:2012规则10.3禁止为类型小于表达式中预期的变量赋值。
要使用MISRA术语,~0xFFFF
的基本类型是无符号的,因为十六进制文字的类型为unsigned int
。在您的系统上,unsigned int
明显大于uint16_t
(int是标准6.3.1.1中的“更高排名”整数类型,即使它们具有相同的大小)。也就是说,uint16_t
的基本类型比unsigned int
更窄,因此您的代码不符合规则10.3。这是您的工具应该报告的内容。
隐藏在MISRA术语背后的实际技术问题是~
运算符是危险的,因为它带有隐式整数提升。这反过来导致代码,例如
uint8_t x=0xFF;
~x << n; // BAD, always a bug
在左移位值0xFFFFFF时调用未定义的行为。
因此,将~
运算符的结果转换为正确的预期类型始终是一种好习惯。在MISRA 2004中甚至有一个明确的规则,现在已经合并为“基本类型”规则。
此外,MISRA(7.2)规定所有整数常量应具有u
或U
后缀。
MISRA-C:符合2012标准的代码如下所示:
uint16_t var;
var = (uint16_t)~0xFFFFu;
或过于迂腐:
var = (uint16_t)~(uint16_t)0xFFFFu;
答案 1 :(得分:0)
当编译器查看右侧时,首先它看到文字0xFFFF。它会自动提升为一个整数,这个整数在系统中是32位(显然来自警告)。现在我们可以将该值设想为0x0000FFFF(整个32位)。当编译器对其执行〜操作时,它变为0xFFFF0000(整个32位)。当您编写var = ~0xFFFF;
时,编译器实际上在分配操作之前看到var = 0xFFFF0000;
。当然,在此任务期间会发生截断...