249

-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

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


2012年2月5日更新:

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

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

4

4 に答える 4

399

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

-2147483648は実際には式です。前に2147483648単項演算子を付けた正のリテラル値です。プラットフォームの範囲の正の側に対して-値が明らかに大きすぎます。プラットフォームで型の範囲が広い場合、コンパイラは型があると自動的に想定する必要があります。(C++11 では、コンパイラは型も考慮する必要があります。)これにより、コンパイラはより大きな型のドメインで評価するようになり、予想どおり、結果は負になります。2147483648intlong int2147483648long intlong 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

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

于 2013-02-04T20:38:46.733 に答える
43

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

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

警告C4146:単項マイナス演算子が符号なし型に適用されましたが、結果はまだ符号なしです

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

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]

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

于 2013-02-04T20:50:19.903 に答える
5

要するに、2147483648オーバーフローは-2147483648、および(-(-2147483648) > 0)ですtrue

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

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

于 2013-02-05T02:42:28.373 に答える
4

-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です。

于 2013-02-05T18:21:40.420 に答える