无符号算术运算中的环绕声

时间:2016-04-04 12:37:04

标签: c misra

在分析以下代码时出现以下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
} 

这是正确的值。

2 个答案:

答案 0 :(得分:1)

首先,176 * 1000不适合16位无符号短路。因此,通过使用MISRA,您可以防止代码中出现严重错误,因为算法是在签名int类型上计算的,其结果隐式显示为无符号短消息。如果你得到预期的结果,那完全是巧合/运气。

请注意,还有其他两个未报告的MISRA违规建议:

  • 不允许使用类似函数的宏(规则19.7)
  • 你应该使用一组预定义的整数typedef,如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;
}

答案 1 :(得分:0)

与整体推广有关:

  

操作时会提升小于int的整数类型   在他们身上表演。如果原始类型的所有值都可以   表示为int,较小类型的值转换为   一个int;否则,它将转换为unsigned 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,结果将为signed int - >类型。 " 14745/2" =" 7372" 6" 206000" +" 7372"将执行,结果将是类型signed int - > 213372
  6. " 213372"将按" 14745"结果" 14"