我有两个有符号整数,我想减去它们。我需要知道它是否溢出。
int one;
int two;
int result = two-one;
if (OVERFLOW) {
printf("overflow");
} else {
printf("no overflow");
}
类似的东西。有没有好的方法来做到这一点?
我有两个有符号整数,我想减去它们。我需要知道它是否溢出。
int one;
int two;
int result = two-one;
if (OVERFLOW) {
printf("overflow");
} else {
printf("no overflow");
}
类似的东西。有没有好的方法来做到这一点?
您需要在它发生之前捕获溢出(或下溢)。一旦发生这种情况,您就处于未定义行为领域,并且所有赌注都已取消。
#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;
}
首先,有符号计算中的溢出会导致 C 中的未定义行为。
其次,暂时忘记 UB 并坚持 2 的补码机器的典型溢出行为:溢出是由结果从第一个操作数向“错误方向”“移动”的事实揭示的,即当结果结束时更大小于具有正第二操作数的第一个操作数(或小于具有负第二操作数的第一个操作数)。
在你的情况下
int one, two;
int result = two - one;
if ((result < two) != (one > 0))
printf("overflow");
您可以以更高的精度执行此操作并进行比较。假设您有 32 位整数。您可以将它们提升为 64 位整数,减去,然后将该结果与转换为 32 位的自身进行比较,然后再转换为 64 位。
我不会这样做int
,因为该语言不能保证大小......也许int32_t
和int64_t
来自<inttypes.h>
(来自 C99)。
如果你在 Windows 上使用可以使用ULongSub()
etc,它会在溢出时返回错误代码。
评估时需要考虑两种情况a-b
:
a-b
可能下溢,当且仅当b>0 && a<0
且a-b < min == a<min+b
a-b
可能会溢出,当且仅当b<0 && a>0
且a-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
}