MISRA警告12.4:整数转换导致截断(否定操作)

时间:2016-11-02 10:36:43

标签: c truncate misra coverity negation

在一个针对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));

2 个答案:

答案 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)规定所有整数常量应具有uU后缀。

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;。当然,在此任务期间会发生截断...