使用警告来解决算术问题

时间:2014-07-22 09:09:05

标签: c bit-manipulation bit

我必须创建两个将无符号/有符号数字相加的函数。但是,编译器给了我以下警告,并且实现似乎没有正常工作(因为它停止)。我相信这里的逻辑可能存在错误,而不是其他语义错误的东西。我是新手,非常感谢任何见解。

警告:

  • 由于数据类型的范围有限,比较总是错误的; //这是第一个函数,比较行
  • 大整数隐式截断为无符号类型; //再次,第一个功能,比较线
  • 隐式常量转换溢出; // if函数底部的if语句

两个函数都采用参数a和b。这是未签名的:

    unsigntype result = a + b;
    if (result < INT_MIN) result = INT_MIN;
    if (result > INT_MAX) result = INT_MAX;
    return result;

签名者:

    signtype result = a + b;
    signtype check = result;
    signtype position = 0;

    while (check >>= 0)
            position++; // get sig fig

    if ((1 << (position + 1)) && result != 0) {
            if ((a > 0 && b > 0)) return INT_MAX;
            return result;
    }

    if ((a < 0 && b < 0) && result > 0) return INT_MIN;
    return result;

编辑:您在此处看到的typedef是占位符,可以由包含的头文件定义的任何整数族类型填充。

另一个编辑:它控制应该使用哪种类型。这两个函数都必须是完全可移植的 - 可以使用按位运算。

#ifndef SAT_TYPE
#define SAT_TYPE 1
#endif

#if SAT_TYPE == 1
typedef signed char signtype;
typedef unsigned char unsigntype;
#define FMT "hh"
#elif SAT_TYPE == 2
typedef signed short signtype;
typedef unsigned short unsigntype;
#define FMT "h"
#elif SAT_TYPE == 3
typedef signed int signtype;
typedef unsigned int unsigntype;
#define FMT ""

4 个答案:

答案 0 :(得分:1)

这只是猜测,但我猜你会在这一行上收到警告之一:

if (result < INT_MIN) result = INT_MIN;

为什么呢?因为result是无符号类型(我假设)而INT_MIN(假设您使用standard INT_MIN)是负数。由于result永远不会小于零,因此检查它是否小于负数将始终为假。

此外,如果unsigntype的类型小于int,则result也不会大于INT_MAX。如果类型等于或大于unsigned int并且您希望将变量值限制为更多,那么这种比较才有意义。 20亿(在int为32位的系统上)。

答案 1 :(得分:0)

if (result < INT_MIN) result = INT_MIN;

测试是将signed int与unsigned int数量进行比较。所以  被提升为unsigned int。将负数解释为无符号整数会产生很大的积极作用 数字,使该条款错误。

了解 Deep C Secrets A subtle bug

答案 2 :(得分:0)

在未签名的情况下:

unsigntype result = a + b;
if (result < INT_MIN) result = INT_MIN;

INT_MIN 否定但无符号类型永远不会小于零,因此此测试确实始终为false。在下一行

if (result > INT_MAX) result = INT_MAX;

你仍然没有说unsigntype是什么,但是如果它不能保持大于INT_MAX的值(例如,如果它是unsigned shortunsigned char)那么这个也总是假的。理想情况下,您应该使用正确的max和min作为实际类型,例如

unsigned short add_ushort(unsigned short a, unsigned short b) {
  if (a > USHRT_MAX - b) return USHRT_MAX;
  return a+b;
}

请注意,我忽略了否定支票,因为这里不可能(你没有说明ab是什么类型,所以我无法判断它们是否为负数你的情况),我写了一个实际有效的溢出检查。


至于签名的案例,我甚至不确定你想要实现的目标。你在这里有一个无限循环:

while (check != 0)
        position++; // doesn't change check, so never exits

其余的看起来......令人费解。也许您可以显示某些输入的预期结果?


现在您已经描述了设置,我建议在现有的预处理器代码中定义特定于类型的最大/最小值:

#if SAT_TYPE == 1
typedef signed char signtype;
typedef unsigned char unsigntype;
#define SIGN_MAX CHAR_MAX
#define SIGN_MIN CHAR_MIN
#define UNSIGN_MAX UCHAR_MAX
#define FMT "hh"
#else
/* ... */
#endif

unsigntype add_unsigned(unsigntype a, unsigntype b) {
  // NB. you need to check for overflow before adding:
  // after the sum has overflowed, it's too late
  if (a > UNSIGN_MAX - b) return UNSIGN_MAX;
  return a+b;
}

signtype add_signed(signtype a, signtype b) {
  if (b < 0 && a < SIGN_MIN - b) return SIGN_MIN;
  if (b > 0 && a > SIGN_MAX - b) return SIGN_MAX;
  return a+b;
}

答案 3 :(得分:0)

在未签名的情况下,这很有趣:

result = a + b ;
if (result < a)
  result = -1 ;