【问题标题】:MISRA warning 12.4: integer conversion resulted in truncation (negation operation)MISRA 警告 12.4:整数转换导致截断(取反操作)
【发布时间】:2017-03-15 15:20:08
【问题描述】:

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

请问你还有什么想法吗?谢谢。

编辑:

然后我尝试使用 32bits 值,结果与以下代码相同:

typedef unsigned int uint32_t; 
uint32_t var; 
var = (uint32_t)(~(uint32_t)(0xFFFF0000u));

【问题讨论】:

  • 你可以使用var = 0;
  • 在你的实际代码中,你真的有~0xffff吗?你知道~0xffff 等于0
  • var = ~0xFFFF; 会收到警告,但var = ~(uint16_t)0xffff; 不会。
  • 谢谢。但是我从静态分析工具(Coverity)收到 MISRA 警告。我的编译器也没有发出警告,但 Coverity 会发出警告。

标签: c truncate misra coverity negation


【解决方案1】:

总结:

假设您使用的是 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(在标准 6.3.1.1 中,int 是比 short 的“排名更高”的整数类型,即使它们的大小相同)。也就是说,uint16_t 是比unsigned int 更窄的基本类型,因此您的代码不符合规则 10.3。这是您的工具应该报告的内容。

隐藏在 MISRA 术语背后的实际技术问题是 ~ 运算符很危险,因为它带有隐式整数提升。这反过来会导致代码,例如

uint8_t x=0xFF; 
~x << n; // BAD, always a bug

在值 0xFFFFFF00 左移时调用未定义的行为。

因此,将~ 运算符的结果转换为正确的预期类型始终是一种好习惯。在 MISRA 2004 中甚至有一个明确的规则,现在已合并到“基本类型”规则中。

此外,MISRA (7.2) 规定所有整数常量都应具有uU 后缀。

符合 MISRA-C:2012 的代码如下所示:

uint16_t var;
var = (uint16_t)~0xFFFFu;

或过于迂腐:

var = (uint16_t)~(uint16_t)0xFFFFu;

【讨论】:

  • 感谢您的开发。不幸的是, var = (uint16_t)~(uint16_t)0xFFFFu;仍然发出警告。此外,除了 12.4 之外,我没有收到任何其他警告。
  • 我曾尝试使用 32bits 值,结果与以下代码相同: typedef unsigned int uint32_t; uint32_t 变量; var = (uint32_t)(~(uint32_t)(0xFFFF0000u));
  • @Ben9000RPM 似乎是一个工具错误。毫不奇怪,市场上 95% 的 MISRA 检查器都已损坏,无法修复。不要混淆您的代码,只需编写绝对安全的var = (uint16_t)~0xFFFFu;,然后忽略该工具。
【解决方案2】:

当编译器查看右侧时,首先它会看到文字 0xFFFF。它会自动提升为系统中的 32 位整数(从警告中可以明显看出)。现在我们可以将该值想象为 0x0000FFFF(整个 32 位)。当编译器对其进行 ~ 操作时,它变为 0xFFFF0000(整个 32 位)。当您编写var = ~0xFFFF; 时,编译器实际上会在分配操作之前看到var = 0xFFFF0000;。当然,在此分配期间会发生截断...

【讨论】:

  • 我的系统是 16 位的。但是也许Coverity没有看到它并把它扩展到32位,我不知道。
  • @Ben9000RPM:您的第一条评论说得通,但第二条提示分析仪有问题(可能是配置问题)...
  • @Ben9000RPM 出于好奇, --type_sizes 开关从您的构建日志中说了什么? Coverity 自动检测类型大小。通常整数是 32 位的,但这可能会有所不同。如果整数也是 16 位的,它会解释为什么你的 32 位示例也会抱怨 - 并且会建议 MISRA 检查器中的错误,它假设整数是 32 位。
  • @Caleb,经过一番调查,Coverity 考虑到整数是 16 位的。有人向他们提出了一个问题。我会及时通知你的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
相关资源
最近更新 更多