3

2つの符号付き整数があり、それらを減算したいと思います。オーバーフローしたかどうかを知る必要があります。

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を1秒間忘れて、2の補数マシンの典型的なオーバーフロー動作に固執します。オーバーフローは、結果が最初のオペランドから「間違った方向」に「移動」するという事実によって明らかになります。つまり、結果が大きくなる場合です。正の第2オペランドを持つ第1オペランドよりも大きい(または負の第2オペランドを持つ第1オペランドよりも小さい)。

あなたの場合

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_tそして(C99int64_tから)から。<inttypes.h>

Windowsを使用している場合は、etcを使用できますULongSub()。これにより、オーバーフロー時にエラーコードが返されます。

于 2009-10-27T20:52:46.453 に答える
0

評価に関して考慮すべき2つのケースがありますa-b

  1. a-bアンダーフローする可能性がb>0 && a<0ありますa-b < min == a<min+b
  2. 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
}
于 2021-12-28T05:32:47.197 に答える