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


241

-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を使用しています。質問の説明を変更しました。

すなわち、この記事では非常に良いreplysがたくさんだ、AndreyTは非常に詳細な入力にどのようにコンパイラの意志行動に説明し、どのようにこの最小の整数が実装されましたを与えました。一方、qPCR4virは、いくつかの関連する「好奇心」と、整数の表現方法を提供しました。とても印象的です!


48
「-2147483648が整数の最小数であることは誰でも知っています」整数のサイズによって異なります。
orlp 2013

14
「私たちは-2147483648が整数の最小数であることを知っています」-整数は無限に多くあるので、最小の整数はないと考えました...何でも。

@Inisheer 4バイトの整数INT_MINでは-9223372036854775808CHAR_BIT16の場合、aが存在する可能性があります。Cは2の補数を必要としないため、CHAR_BIT == 8and sizeof(int== 4) `を使用しても取得でき-9223372036854775807ます。
12431234123412341234123 2017

回答:


391

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

-2147483648は実際には式です:前に2147483648単項演算-子がある正のリテラル値。値2147483648intプラットフォームの範囲のプラス側には大きすぎるようです。タイプ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

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


78
これが、これが行われる理由でもあります#define INT_MIN (-2147483647 - 1)
orlp 2013

5
@ RichardJ.RossIII-clangを使用すると、64ビット型のリテラルが得られますint。OPの実装には64ビット型がない場合があります。
Carl Norum、2013

1
@ RichardJ.RossIII:この動作は実装定義/未定義であると思います。
オリバーチャールズワース2013

3
「負の数」がそのように解析されないとは思いもしませんでした。理由はわかりません。それ-1.0が負のdouble値として解析されることを願っていますね。
leemes

6
@ qPCR4vir:いいえ。あなたの答えに対するコメントで書いたように、この場合、最新のCもC ++も符号なしの型を使用できません(接尾辞のない10進定数を使用)。unsigned long intこのコンテキストでは最初の標準C(C89 / 90)のみが許可されていましたが、C99ではこの許可が削除されました。CおよびC ++の接尾辞のないリテラルには、符号付きの型が必要です。署名付きの型が機能するときにここで署名なしの型が表示される場合は、コンパイラが壊れていることを意味します。署名された型が機能しないときにここで署名されていない型が表示された場合、これは未定義の動作の特定の症状です。
AnT 2013

43

コンパイラー(VC2012)は、値を保持できる「最小」整数に昇格します。最初のケースでは、signed int(とlong int)は、(符号が適用される前に)することができないが、unsigned int缶:2147483648有しunsigned int ???? タイプ。秒であなたはintから強制しますunsigned

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_tchar32_t、または wchar_tその整数変換ランク(4.13)を以下INTのランクよりもタイプのprvalueに変換することができるint場合はint、ソース・タイプのすべての値を表すことができます。それ以外の場合は、ソースのprvalueをtypeのprvalueに変換できますunsigned int


3
qPCR4vir @:でC89 / 90コンパイラは型を使用することになったintlong intunsigned long int接尾辞なしの10進定数の表現するために。これは、接尾辞なしの10進定数に符号なしの型を使用できる唯一の言語でした。C ++ 98では、intまたはlong intでした。符号なしの型は許可されていません。C(C99以降)もC ++も、コンパイラーがこのコンテキストで符号なしの型を使用することを許可しません。もちろん、コンパイラーは、署名された型が機能しない場合は、署名されていない型を自由に使用できますが、これは未定義の動作の特定の兆候にすぎません。
AnT 2013

@AndreyT。すごい!いい加減に、あなたの厳しさ。VC2012は壊れていますか?
qPCR4vir 2013

@ qPCR4vir:AFAIK、VC2012はまだC ++ 11コンパイラではありません(そうですか?)。つまり、を使用するかintlong intを表す必要があり2147483648ます。また、VC2012で私の知る限り、両方intlong int32ビットのタイプです。これは、VC2012ではリテラル2147483648未定義の動作につながることを意味します。動作が定義されていない場合、コンパイラは何でも実行できます。これは、VC2012が壊れていないことを意味します。それは単に誤解を招く診断メッセージを出しました。動作が完全に未定義であることを通知する代わりに、符号なしの型を使用することにしました。
AnT 2013

@AndreyT:ソースコードにsignedの最大値を超える接尾辞なしの10進リテラルが含まれlongていて、診断を発行する必要がない場合、コンパイラは鼻の悪魔を自由に出力できると言っていますか?それは壊れているようです。
スーパーキャット2013

VS2008と同じ「警告C4146」とG ++の「この10進定数はISO C90でのみ符号なし」
spyder

6

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

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

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


4

-2147483648は実際に2147483648は否定(-)が適用されているため、数値は期待したものとは異なります。これは実際には次の疑似コードに相当します。operator -(2147483648)

今、コンパイラが持っていると仮定するとsizeof(int)等しい4CHAR_BITとして定義され8てしまい、その、2147483648整数(最大符号付きの値をオーバーフロー2147483647)。それで、最大プラス1は何ですか?それを4ビット、2秒の補数整数で解決しましょう。

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

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


4ビットの数値の場合、2の補数の否定-8はまだ-8です。
ベンフォークト

ただし、-8は負の8ではなく0-8として解釈されます。8は4ビットの符号付き整数をオーバーフローします
Cole Johnson

-(8)C ++でどちらが同じであるかを検討してください。これ-8は、負のリテラルではなくリテラルに適用される否定です。リテラルは8であり、符号付き4ビット整数には適合しないため、符号なしでなければなりません。パターンは1000です。これまでのところ、あなたの答えは正しいです。10004ビットでの2の補数の否定はであり1000、符号付きか符号なしかは関係ありません。あなたの答えは、「ビットを符号付き整数として解釈する」と言っています。これは-8、2の補数の否定の後に、否定の前と同じように値を作成します。
Ben Voigt

もちろん、「4ビットC ++」では、「ビットを符号付き整数ステップとして解釈する」ことはできません。リテラルは、それを表現できる最小の型になります。これは、符号なし4ビット整数です。リテラルの値は8です。否定が適用され(16を法とする)、最終的な答えはになり8ます。エンコードは1000のままですが、符号なしタイプが選択されたため、値は異なります。
Ben Voigt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.