3

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

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

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

类似的东西。有没有好的方法来做到这一点?

4

4 回答 4

13

您需要在它发生之前捕获溢出(或下溢)。一旦发生这种情况,您就处于未定义行为领域,并且所有赌注都已取消。

#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;
}
于 2009-10-27T21:47:34.010 回答
8

首先,有符号计算中的溢出会导致 C 中的未定义行为。

其次,暂时忘记 UB 并坚持 2 的补码机器的典型溢出行为:溢出是由结果从第一个操作数向“错误方向”“移动”的事实揭示的,即当结果结束时更大小于具有正第二操作数的第一个操作数(或小于具有负第二操作数的第一个操作数)。

在你的情况下

int one, two;

int result = two - one;
if ((result < two) != (one > 0))
  printf("overflow");
于 2009-10-27T20:55:03.093 回答
0

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

我不会这样做int,因为该语言不能保证大小......也许int32_tint64_t来自<inttypes.h>(来自 C99)。

如果你在 Windows 上使用可以使用ULongSub()etc,它会在溢出时返回错误代码。

于 2009-10-27T20:52:46.453 回答
0

评估时需要考虑两种情况a-b

  1. a-b可能下溢,当且仅当b>0 && a<0a-b < min == a<min+b
  2. a-b可能会溢出,当且仅当b<0 && a>0a-b > max == -b>max-a

这导致我们将a案例简化为

#include <limits.h>

int sub_invokes_UB(int a, int b) {
  if ((b > 0) && (a < INT_MIN + b)) ub = 1; // error
  if ((b < 0) && (a > INT_MAX + b)) ub = 1; // error
  return 0; // ok
}
于 2021-12-28T05:32:47.197 回答