如何在C中减去两个带符号的32位数时检测溢出?

时间:2009-10-27 20:48:30

标签: c integer-overflow

我有两个有符号的整数,我想减去它们。我需要知道它是否溢出。

int one;
int two;
int result = two-one;

if (OVERFLOW) {
    printf("overflow");
} else {
    printf("no overflow");
}

这样的事情。有没有办法做到这一点?

3 个答案:

答案 0 :(得分:10)

你需要在之前发现溢出(或下溢)。一旦发生这种情况,你就会进入未定义的行为土地并且所有的赌注都已关闭。

#include <limits.h>
#include <stdio.h>

int sum_invokes_UB(int a, int b) {
  int ub = 0;
  if ((b < 0) && (a < INT_MIN - b)) ub = 1;
  if ((b > 0) && (a > INT_MAX - b)) ub = 1;
  return ub;
}

int main(void) {
  printf("(INT_MAX-10) + 8: %d\n", sum_invokes_UB(INT_MAX - 10, 8));
  printf("(INT_MAX-10) + 100: %d\n", sum_invokes_UB(INT_MAX - 10, 100));
  printf("(INT_MAX-10) + INT_MIN: %d\n", sum_invokes_UB(INT_MAX - 10, INT_MIN));
  printf("100 + INT_MIN: %d\n", sum_invokes_UB(100, INT_MIN));
  printf("-100 + INT_MIN: %d\n", sum_invokes_UB(-100, INT_MIN));
  printf("INT_MIN - 100: %d\n", sum_invokes_UB(INT_MIN, -100));
  return 0;
}

答案 1 :(得分:6)

首先,签名计算中的溢出会导致C中的未定义行为。

其次,忘记UB一秒钟,并坚持2补码机器的典型溢出行为:溢出是由于结果从第一个操作数“错误的方向”“移动”,即结果最终大于第一个操作数,第二个操作数为正(或小于第二个操作数为第一个操作数)。

在你的情况下

int one, two;

int result = two - one;
if ((result < two) != (one > 0))
  printf("overflow");

答案 2 :(得分:1)

您可以以更高的精度进行比较。假设你有32位整数。您可以将它们提升为64位整数,减去,然后将该结果与自身转换为32位然后再将其再次转换为64位。

我不会这样做int,因为该语言无法保证大小... int32_t和来自int64_t的{​​{1}} (来自C99)。

如果您使用的是Windows,则可以使用<inttypes.h>等,这会在溢出时返回错误代码。