web-dev-qa-db-ja.com

未定義の動作なしにCで符号付き整数オーバーフローをチェックする方法は?

(1):

// assume x,y are non-negative
if(x > max - y) error;

(2):

// assume x,y are non-negative
int sum = x + y;
if(sum < x || sum < y) error;

どちらが好ましいか、またはより良い方法があります。

26
Ganker

整数オーバーフローは、Cの「未定義の動作」の標準的な例です(符号なし整数の演算はオーバーフローしないため、代わりにラップアラウンドに定義されていることに注意してください)。これは、x + yを実行した後、オーバーフローした場合は、すでにホースがかかっていることを意味します。チェックを行うには遅すぎます-プログラムはすでにクラッシュしている可能性があります。ゼロによる除算をチェックするようなものだと考えてください。除算が実行されてからチェックするまで待つと、もう手遅れになります。

したがって、これは、方法(1)が唯一の正しい方法であることを意味します。 maxには、INT_MAX<limits.h>を使用できます。

xおよび/またはyが負になる可能性がある場合は、より困難です。テスト自体がオーバーフローを引き起こさないようにテストを行う必要があります。

if ((y > 0 && x > INT_MAX - y) ||
    (y < 0 && x < INT_MIN - y))
{
    /* Oh no, overflow */
}
else
{
    sum = x + y;
}
60
caf

オーバーフローをチェックできるのは、unsigned整数と算術演算のみです。

unsigned a,b,c;
a = b + c;
if (a < b) {
    /* overflow */
}

符号付き整数でのオーバーフローの動作はCでは未定義ですが、ほとんどのマシンで使用できます

int a,b,c;
a = b + c;
if (c < 0 ? a > b : a < b) {
    /* overflow */
}

これは、あらゆる種類の飽和演算を使用するマシンでは機能しません。

6
Chris Dodd