web-dev-qa-db-ja.com

符号付き/符号なしの比較

次のコードが指定された場所で警告を発行しない理由を理解しようとしています。

//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX  2147483647 /* maximum (signed) int value */
            /* = 0x7fffffff */

int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;

if(a < b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a == b) // no warning <--- warning expected here
    c = true;
if(((unsigned int)a) == b) // no warning (as expected)
    c = true;
if(a == ((int)b)) // no warning (as expected)
    c = true;

私はそれがバックグラウンドプロモーションと関係があると思ったが、最後の2つはそうでないと言っているようだ。

私の考えでは、最初の==比較は、他と同じくらい符号付き/符号なしの不一致ですか?

77
Peter

符号付きと符号なしを比較する場合、コンパイラは符号付きの値を符号なしに変換します。平等のために、これは関係ありません、-1 == (unsigned) -1。他の比較では重要です。次のとおりです:_-1 > 2U_。

編集:参照:

5/9:(式)

算術または列挙型のオペランドを期待する多くの二項演算子は、変換を引き起こし、同様の方法で結果の型を生成します。目的は、結果の型でもある共通の型を生成することです。このパターンは、通常の算術変換と呼ばれ、次のように定義されます。

  • いずれかのオペランドがlong double型の場合、もう一方はlong doubleに変換されます。

  • それ以外の場合、一方のオペランドがdoubleであれば、他方はdoubleに変換されます。

  • それ以外の場合、一方のオペランドがfloatであれば、他方はfloatに変換されます。

  • それ以外の場合、整数のプロモーション(4.5)は両方のオペランドで実行されます。54)

  • 次に、一方のオペランドが符号なしlongの場合、他方は符号なしlongに変換されます。

  • それ以外の場合、一方のオペランドがlong intでもう一方がunsigned intであり、long intがunsigned intのすべての値を表すことができる場合、unsigned intはlong intに変換されます。それ以外の場合、両方のオペランドは符号なしlong intに変換されます。

  • それ以外の場合、一方のオペランドが長い場合、他方はlongに変換されます。

  • それ以外の場合、一方のオペランドが符号なしの場合、他方は符号なしに変換されます。

4.7/2:(積分変換)

宛先タイプが符号なしの場合、結果の値は、ソース整数と一致する最小の符号なし整数です(モジュロ2n ここで、nは符号なしの型を表すために使用されるビット数です)。 [注:2の補数表現では、この変換は概念的なものであり、ビットパターンに変更はありません(切り捨てがない場合)。 ]

EDIT2:MSVC警告レベル

もちろん、MSVCのさまざまな警告レベルについて警告されるのは、開発者による選択です。私が見るように、署名された/署名されていない平等に対する彼らの選択対より大きい/より小さい比較は理にかなっています、これはもちろん完全に主観的です:

_-1 == -1_は-1 == (unsigned) -1と同じことを意味します-直感的な結果だと思います。

_-1 < 2_ しない-1 < (unsigned) 2と同じ意味-これは一見直感的ではなく、IMOは「以前の」警告に値します。

81
Erik

署名された/署名されていない警告が重要であり、プログラマーがそれらに注意を払わなければならない理由は、次の例で示されています。

このコードの出力を推測しますか?

#include <iostream>

int main() {
        int i = -1;
        unsigned int j = 1;
        if ( i < j ) 
            std::cout << " i is less than j";
        else
            std::cout << " i is greater than j";

        return 0;
}

出力:

i is greater than j

びっくりした?オンラインデモ: http://www.ideone.com/5iCxY

ボトムライン:、一方のオペランドがunsignedの場合、もう一方のオペランドは暗黙的にunsignedifそのタイプは署名されています!

27
Nawaz

==演算子は、ビット単位の比較を行います(単純な除算により、0かどうかを確認します)。

比較よりも小さい/大きいのは、数値の符号により大きく依存します。

4ビットの例:

1111 = 15?または-1?

1111 <0001の場合...あいまいです...

しかし、もしあなたが1111 == 1111を持っているなら...それは同じことです。

3
Yochai Timmer

2の補数(最新のプロセッサ)を使用して値を表すシステムでは、バイナリ形式でも同じです。これが、コンパイラがa == bについて文句を言わない理由かもしれません。

そして、私にとっては、奇妙なコンパイラーがa ==((int)b)について警告しません。整数の切り捨ての警告などが表示されるはずです。

1
Hossein