web-dev-qa-db-ja.com

(-2147483648> 0)C ++でtrueを返しますか?

-2147483648は32ビットの整数型の最小の整数ですが、if(...)文でオーバーフローするようです:

if (-2147483648 > 0)
    std::cout << "true";
else
    std::cout << "false";

これにより、テストでtrueが出力されます。ただし、-2147483648を整数にキャストすると、結果は異なります。

if (int(-2147483648) > 0)
    std::cout << "true";
else
    std::cout << "false";

これはfalseを出力します。

よくわかりません。誰でもこれについて説明できますか?


アップデート02-05-2012:

コメントをありがとう、私のコンパイラでは、intのサイズは4バイトです。いくつかの簡単なテストにVCを使用しています。質問の説明を変更しました。

AndreyT は、この投稿で非常に良い回答をたくさん送ってくれました。このような入力に対してコンパイラがどのように振る舞うか、そしてこの最小整数がどのように実装されたかについて非常に詳細な説明をしました。 qPCR4vir 一方、関連する「好奇心」と整数の表現方法を示しました。とても印象的!

238
benyl

-2147483648は「数字」ではありません。 C++言語は、負のリテラル値をサポートしていません。

-2147483648は実際には式です。正のリテラル値2147483648の前に単項-演算子があります。プラットフォーム上のint範囲のプラス側には、値2147483648が大きすぎるようです。プラットフォームでlong int型の範囲が広い場合、コンパイラは2147483648long int型であると自動的に想定する必要があります。 (C++ 11では、コンパイラはlong long int型も考慮する必要があります。)これにより、コンパイラは大きな型のドメインで-2147483648を評価するようになり、結果は負の値になります。 。

ただし、明らかにあなたの場合、long intの範囲はintの範囲と同じであり、一般的に、プラットフォームにはintより大きい範囲の整数型はありません。これは、正の定数2147483648が利用可能なすべての符号付き整数型をオーバーフローさせることを正式に意味します。つまり、プログラムの動作が未定義であることを意味します。 (言語仕様が診断メッセージを要求する代わりに、そのような場合に未定義の動作を選択することは少し奇妙ですが、それはそうです。)

実際には、振る舞いが未定義であることを考慮すると、2147483648は実装に依存する負の値として解釈され、単項-が適用された後に正になることがあります。あるいは、一部の実装では、値を表すために符号なしの型を使用することを決定する場合があります(たとえば、C89/90コンパイラではunsigned long intを使用する必要がありますが、C99またはC++では使用しません)。動作はとにかく未定義なので、実装は何でもできます。

補足として、これがINT_MINのような定数が通常次のように定義される理由です。

#define INT_MIN (-2147483647 - 1)

一見単純な代わりに

#define INT_MIN -2147483648

後者は意図したとおりに機能しません。

386
AnT

コンパイラー(VC2012)は、値を保持できる「最小」整数にプロモートします。最初のケースでは、signed int(およびlong int)は(符号が適用される前)できませんが、unsigned intは次のことができます:2147483648 HAS unsigned int????タイプ。 2番目では、intからunsignedを強制します。

const bool i= (-2147483648 > 0) ;  //   --> true

警告C4146:単項マイナス演算子はunsigned型に適用されます、結果はまだunsigned

関連する「好奇心」は次のとおりです。

const bool b= (-2147483647      > 0) ; //  false
const bool i= (-2147483648      > 0) ; //  true : result still unsigned
const bool c= ( INT_MIN-1       > 0) ; //  true :'-' int constant overflow
const bool f= ( 2147483647      > 0) ; //  true
const bool g= ( 2147483648      > 0) ; //  true
const bool d= ( INT_MAX+1       > 0) ; //  false:'+' int constant overflow
const bool j= ( int(-2147483648)> 0) ; //  false : 
const bool h= ( int(2147483648) > 0) ; //  false
const bool m= (-2147483648L     > 0) ; //  true 
const bool o= (-2147483648LL    > 0) ; //  false

C++ 11標準

2.14.2整数リテラル[Lex.icon]

整数リテラルは、ピリオドまたは指数部を持たない一連の数字です。整数リテラルには、ベースを指定するプレフィックスと、タイプを指定するサフィックスが含まれる場合があります。

整数リテラルの型は、その値を表すことができる対応するリストの最初のものです。

enter image description here

整数リテラルがリスト内のどのタイプでも表現できず、拡張整数タイプ(3.9.1)がその値を表現できる場合、その拡張整数タイプを持つことができます。リテラルのリスト内のすべての型が署名されている場合、拡張整数型は署名されます。リテラルのリストにあるすべての型が符号なしの場合、拡張整数型は符号なしです。リストに符号付きと符号なしの両方の型が含まれる場合、拡張整数型は符号付きまたは符号なしのいずれかになります。変換単位の1つに、許可された型で表現できない整数リテラルが含まれている場合、プログラムの形式は正しくありません。

そして、これらは標準の整数のプロモーション規則です。

4.5インテグラルプロモーション[conv.prom]

整数変換ランク(4.13)がintのランクより小さいboolchar16_tchar32_t、またはwchar_t以外の整数型のprvalueは、intがソース型のすべての値を表すことができる場合、タイプintのprvalueに変換できます;それ以外の場合、ソースprvalueは、タイプunsigned intのprvalueに変換できます。

43
qPCR4vir

要するに、2147483648-2147483648にオーバーフローし、(-(-2147483648) > 0)trueです。

これ は、2147483648がバイナリでどのように見えるかです。

さらに、符号付きバイナリ計算の場合、最上位ビット(「MSB」)は符号ビットです。 この質問 理由の説明に役立つ場合があります。

7
drzymala

-2147483648は実際には2147483648に否定(-)が適用されているため、数値は期待したものではありません。実際には、この擬似コードと同等です:operator -(2147483648)

ここで、コンパイラの_sizeof(int)4に等しく、CHAR_BIT8として定義されていると仮定すると、2147483648は整数の最大符号値(2147483647)をオーバーフローさせます。では、最大プラス1は何ですか? 4ビット、2の補数整数でそれを解決しましょう。

待つ! 8は整数をオーバーフローします!私たちは何をしますか? 1000の符号なし表現を使用し、ビットを符号付き整数として解釈します。この表現により、-8に2の補数の否定が適用され、8が生成されます。これは、ご存じのとおり、0よりも大きい値です。

これが、<limits.h>(および<climits>)が一般的にINT_MIN((-2147483647) - 1)として定義する理由です-最大の符号付き整数(0x7FFFFFFF)が否定され(0x80000001)、その後減少します(0x80000000)。

4
Cole Johnson