94

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

//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つはそうではないようです.

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

4

5 に答える 5

107

符号付きと符号なしを比較すると、コンパイラは符号付きの値を符号なしに変換します。平等の場合、これは問題ではありません-1 == (unsigned) -1。他の比較では重要です。たとえば、次のようになります-1 > 2U

編集:参考文献:

5/9: (表情)

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

  • いずれかのオペランドが long double 型の場合、もう一方は long double に変換されます。
  • それ以外の場合、いずれかのオペランドが double の場合、もう一方は double に変換されます。
  • それ以外の場合、いずれかのオペランドが float の場合、もう一方は float に変換されます。
  • それ以外の場合、積分昇格 (4.5) は両方のオペランドで実行されなければならない.54)
  • 次に、いずれかのオペランドが unsigned long の場合、もう一方は unsigned long に変換されます。
  • それ以外の場合、一方のオペランドが long int でもう一方の unsigned int である場合、long int が unsigned int のすべての値を表すことができる場合、unsigned int は long int に変換されます。それ以外の場合は、両方のオペランドが unsigned long int に変換されます。
  • それ以外の場合、いずれかのオペランドが long の場合、もう一方は long に変換されます。
  • それ以外の場合、いずれかのオペランドが符号なしの場合、もう一方は符号なしに変換されます。

4.7/2: (整数変換)

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

EDIT2: MSVC 警告レベル

もちろん、MSVC のさまざまな警告レベルで警告されるのは、開発者の選択です。私が見ているように、符号付き/符号なしの同等性とより大きい/小さい比較に関する彼らの選択は理にかなっていますが、これはもちろん完全に主観的です:

-1 == -1と同じ意味-1 == (unsigned) -1です - 直感的な結果だと思います。

-1 < 2 と同じ意味ではありません-1 < (unsigned) 2- これは一見すると直感的ではなく、IMO は「より早い」警告に値します。

于 2011-03-24T08:27:45.813 に答える
36

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

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

#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に暗黙的に変換されます!unsigned

于 2011-03-24T08:49:52.387 に答える
5

== 演算子は、ビットごとの比較を行うだけです (単純な除算によって、0 かどうかを確認します)。

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

4 ビット 例:

1111 = 15 ? または -1 ?

したがって、1111 < 0001 の場合 ... あいまいです ...

しかし、もしあなたが 1111 == 1111 を持っているなら ... 意図したわけではありませんが、同じことです。

于 2011-03-24T08:28:12.023 に答える
2

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

そして、私にとっては、コンパイラがa == ((int)b)について警告しないのは奇妙なことです。整数の切り捨ての警告か何かを与えるべきだと思います。

于 2011-03-24T08:29:50.227 に答える