5

加算の結果がオーバーフローするかどうかをチェックするために使用される C のバグのあるコードを見ました。で問題なく動作charしますが、引数がintであり、理由がわからなかった場合、間違った答えが返されます。引数
付きのコードは次のとおりです。short

short add_ok( short x, short y ){
    short sum = x+y;
    return (sum-x==y) && (sum-y==x);
}

このバージョンは正常に動作します。引数を に変更すると問題が発生しますint( で確認 できますINT_MAX) 。

4

4 に答える 4

5

あなたのコードでは、 が と同じサイズでない限り、加算はオーバーフローしません。デフォルトの昇格により、は の値に対して実行され、 に昇格され、結果は実装定義の方法で に切り捨てられます。intshortx+yxyintshort

なぜ単純にしないのですか:return x+y<=SHRT_MAX && x+y>=SHRT_MIN;

于 2012-07-12T21:03:24.453 に答える
3

C プログラミング言語では、符号付き整数をより小さな符号付き整数、たとえば char (簡単にするため) に変換すると、実装定義の方法になります。多くのシステムやプログラマーはラップアラウンド オーバーフローを想定していますが、これは標準ではありません。では、ラップアラウンド オーバーフローとは何ですか?

2 の補数システムでのラップアラウンド オーバーフローは、現在の型で値を提示できなくなった場合に、提示可能な最大数または最小数にワープするように発生します。では、これはどういう意味ですか?見てください。

signed char では、表示できる最大値は 127 で、最小値は -128 です。次に、「char i = 128」とすると、i に格納されている値が -128 になります。値が符号付き整数型よりも大きいため、最小値にラップし、「char i = 129」の場合、i には -127 が含まれます。見えますか?端が最大に達すると、もう一方の端 (符号) にラップします。逆に、「char i = -129」の場合、i は 127 を含み、「char i = -130」の場合、最大値に達して最高値をラップしたため、126 を含みます。

(最高) 127、126、125、...、-126、-127、-128 (最低)

値が非常に大きい場合は、その範囲で表現できる値に達するまでラップアラウンドを続けます。

char 型のラップアラウンド ポイント


更新: and とはint反対に機能しない理由は、両方の数値が加算されるとオーバーフローの可能性があるためです ( 、、またはであっても、整数の昇格を忘れないでください)。これらは in 式に昇格されるため、次の行では切り捨てられずに再び表されます。charshortintshortchar"short"charintint

return (sum-x==y) && (sum-y==x);

そのため、後で詳しく説明するようにオーバーフローが検出されますが、の場合intは何にも昇格されないため、オーバーフローが発生します。たとえば、私が行う場合INT_MAX+1、結果は INT_MIN であり、INT_MIN-1 == INT_MAX によるオーバーフローをテストした場合、結果は TRUE です! これは、"short" と char が int に昇格され、評価され、切り捨てられる (オーバーフローする) ためです。ただし、 int は大きなサイズに昇格されないため、最初にオーバーフローしてから評価されます。

プロモーションなしの char 型を考えて、上の図を使用してオーバーフローを作成し、確認してみてください。オーバーフローの原因となる値を加算または減算すると、元の場所に戻ることがわかります。ただし、これは C では発生しません。char と "short" が int に昇格されるため、オーバーフローが検出されます。これは、より大きなサイズに昇格されないため、int では当てはまりません。

更新の終了


あなたの質問については、MinGW と Ubuntu 12.04 でコードを確認しましたが、問題なく動作しているようです。後で、short が int より小さく、値が int の範囲を超えないシステムでコードが実際に機能することがわかりました。この行:

return (sum-x==y) && (sum-y==x);

"sum-x" と "y" は (int) として評価されるため、(割り当てられた場合) 前の行で発生したラップアラウンドは発生しないため、true です。

short sum = x+y;

これがテストです。最初に 32767 を入力し、2 番目に 2 を入力した場合:

short sum = x+y;

ラップアラウンドのため、sum には -32767 が含まれます。ただし、次の場合:

return (sum-x==y) && (sum-y==x);

"sum-x" (-32767 - 32767) は、ラップラウンドが発生した場合にのみ y (2) と等しくなります (その場合はバグがあります)。 65534 は y と等しくないため、正しい検出につながります。

使用したコードは次のとおりです。

#include <stdio.h>

short add_ok( short x, short y ){
    short sum = x+y;
    return (sum-x==y) && (sum-y==x);
}

int main(void) {

    short i, ii;
    scanf("%hd %hd", &i, &ii);
    getchar();

    printf("%hd", add_ok(i, ii));

    return 0;
}

ここここをチェックしてください。

作業中のアーキテクチャと、テストした実験値を提供する必要があります。これは、誰もがあなたの言うことに直面しているわけではなく、質問の実装定義の性質のためです。

参照: C99 6.3.1.3はこちら、GNU C マニュアルはこちら

于 2012-07-13T04:58:29.310 に答える