-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 一方、関連する「好奇心」と整数の表現方法を示しました。とても印象的!
-2147483648
は「数字」ではありません。 C++言語は、負のリテラル値をサポートしていません。
-2147483648
は実際には式です。正のリテラル値2147483648
の前に単項-
演算子があります。プラットフォーム上のint
範囲のプラス側には、値2147483648
が大きすぎるようです。プラットフォームでlong int
型の範囲が広い場合、コンパイラは2147483648
がlong 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
後者は意図したとおりに機能しません。
コンパイラー(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]
…
整数リテラルは、ピリオドまたは指数部を持たない一連の数字です。整数リテラルには、ベースを指定するプレフィックスと、タイプを指定するサフィックスが含まれる場合があります。
…
整数リテラルの型は、その値を表すことができる対応するリストの最初のものです。
整数リテラルがリスト内のどのタイプでも表現できず、拡張整数タイプ(3.9.1)がその値を表現できる場合、その拡張整数タイプを持つことができます。リテラルのリスト内のすべての型が署名されている場合、拡張整数型は署名されます。リテラルのリストにあるすべての型が符号なしの場合、拡張整数型は符号なしです。リストに符号付きと符号なしの両方の型が含まれる場合、拡張整数型は符号付きまたは符号なしのいずれかになります。変換単位の1つに、許可された型で表現できない整数リテラルが含まれている場合、プログラムの形式は正しくありません。
そして、これらは標準の整数のプロモーション規則です。
4.5インテグラルプロモーション[conv.prom]
整数変換ランク(4.13)がintのランクより小さい
bool
、char16_t
、char32_t
、またはwchar_t
以外の整数型のprvalueは、int
がソース型のすべての値を表すことができる場合、タイプint
のprvalueに変換できます;それ以外の場合、ソースprvalueは、タイプunsigned int
。のprvalueに変換できます。
-2147483648
は実際には2147483648
に否定(-
)が適用されているため、数値は期待したものではありません。実際には、この擬似コードと同等です:operator -(2147483648)
ここで、コンパイラの_sizeof(int)
が4
に等しく、CHAR_BIT
が8
として定義されていると仮定すると、2147483648
は整数の最大符号値(2147483647
)をオーバーフローさせます。では、最大プラス1は何ですか? 4ビット、2の補数整数でそれを解決しましょう。
待つ! 8は整数をオーバーフローします!私たちは何をしますか? 1000
の符号なし表現を使用し、ビットを符号付き整数として解釈します。この表現により、-8
に2の補数の否定が適用され、8
が生成されます。これは、ご存じのとおり、0
よりも大きい値です。
これが、<limits.h>
(および<climits>
)が一般的にINT_MIN
を((-2147483647) - 1)
として定義する理由です-最大の符号付き整数(0x7FFFFFFF
)が否定され(0x80000001
)、その後減少します(0x80000000
)。