【问题标题】:Wraparound in unsigned arithmetic operation无符号算术运算中的回绕
【发布时间】:2016-04-04 12:37:04
【问题描述】:

分析以下代码时出现以下 MISRA 违规:

#define z  (USHORT)14745

#define Convert(x) ((((USHORT)x*(unsigned short)1000) + ((z) / (USHORT)2)) /(z))

static const USHORT array [2] = 

{
   Convert(176), -> Line "1"
   Convert(206)  -> Line "2"
};

在“1”、“2”两行都检测到以下 MISRA 违规:

  • 积分提升:unsigned short 提升为 unsigned int。 参考 - ISO:C90-6.2.1.1 字符和整数

  • 常量:无符号算术运算中的回绕。 MISRA-C:2004 规则 12.11;参考 - ISO:C90-6.1.2.5 类型

  • 此强制转换的结果被隐式转换为另一种类型。

我的问题是:为什么在这个操作中会有一个环绕?!

注意:当我使用调试器检查array 的值时:

array [2] = 
{
  12,
  14
} 

哪些是正确的值。

【问题讨论】:

  • 因为176000206000都超过了USHORT可以容纳的值。
  • 凌乱的“转换”行应该是什么?宏的一部分?据我所知,它不是有效的 C。
  • @Vane,但是最后的结果是正确的,为什么?!
  • @Lundin,检查最后的编辑
  • 规则 12.11 是建议性的。假设您在转换中“幸运”,并且有规则可以防止您“不幸”..

标签: c misra


【解决方案1】:

首先,176 * 1000 不适合 16 位无符号短整数。因此,通过使用 MISRA,您可以防止代码中出现严重错误,因为该算法是根据有符号的 int 类型计算的,并且它的结果隐含地显示为无符号短。如果你得到了预期的结果,那完全是巧合/运气。

请注意,还有另外两个未报告的建议性 MISRA 违规行为:

  • 不允许使用类似函数的宏(规则 19.7)
  • 您应该使用一组预定义的整数类型定义,例如 stint.h(规则 6.3)

这两个都是非常好的规则,不应该忽略。 (它也应该警告你使用不带 'u' 后缀的文字。)

解决方法是用类型安全函数替换混乱的宏,该函数不包含隐式提升(给定 32 位 int):

uint16_t convert (uint16_t x)
{
  const uint16_t z = 14745u;
  uint32_t result32;

  result32 = (uint32_t)x * 1000ul + (uint32_t)z / 2ul / (uint32_t)z
  return (uint16_t)result32;
}

【讨论】:

  • "因为算法是在有符号整数上计算的" 你的意思是 UNsigned int 吗?
  • @ArmiaWagdy 不,所有小整数类型,例如 unsigned short 都会在表达式中使用时隐式提升为(有符号)int。这是微妙而危险的,也是为什么 MISRA 充满了非常完善的规则来防止此类错误。 MISRA 的主要任务之一实际上似乎是教程序员了解隐式晋升的危险。有很多资深的 C 程序员不知道 C 中的各种隐式类型提升规则。我承认,在 2004 年阅读 MISRA 之前,我自己并不知道。
【解决方案2】:

与积分促销有关:

小于 int 的整数类型在操作时被提升 对他们进行。如果原始类型的所有值都可以 表示为 int,较小类型的值转换为 一个整数;否则,将其转换为无符号整数。

这样,Convert(206) [((((unsigned short)206*(unsigned short)1000) + ((z) / (USHORT)2)) /(z))] 宏将按如下方式执行:

  1. “206”将提升为带符号整数。
  2. “1000”将提升为带符号整数。
  3. 将执行“206 * 1000”操作,结果也是signed int 类型 -> “206000”。
  4. z, 2 将被提升为signed int。
  5. 将执行 z / 2 操作,结果将是有符号 int 类型 -> "14745 / 2" = "7372" 6."206000" + "7372" 会执行,结果是signed int -> 213372
  6. “213372”将除以“14745”得到“14”

【讨论】:

  • 从技术上讲,整数常量已经是int 类型。尽管您将其中一些投给了 USHORT,但这些将被提升回int。这意味着这个 sn-p 中的所有演员都是完全多余的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-17
  • 1970-01-01
  • 2022-01-07
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
  • 2018-08-17
相关资源
最近更新 更多