符号なし変数に負の値を割り当てるとどうなりますか?


82

符号なし変数に負の値を割り当てるとどうなるか知りたいと思いました。

コードは次のようになります。

unsigned int nVal = 0;
nVal = -5;

コンパイラエラーは発生しませんでした。私がプログラムを実行したときnVal、奇妙な値が割り当てられました!2の補数の値が割り当てられる可能性がありnValますか?


1
私の勘(まだ標準でそれを見つけることができていません)は、動作が技術的に定義されていないということです。さらに、私はあなたが見つけることができるほとんどすべてのコンパイラであなたが期待するものを見るだろうと思う。したがって、通常はその動作が見られますが、それを当てにするのはおそらく良い考えではありません。
sblom 2010

6
未定義ではありませんが(§4.7/ 2を参照)、表現(2の補数など)は標準で義務付けられていません。
Georg Fritzsche 2010

@gf(以下など)、かっこいい。実際、動作は期待どおりに明示的に定義されているようです、@ viswanathan。
sblom 2010

3
2行目はnVal = (unsigned int) -5;。と同等です。-5toのキャストは6.3.1.3unsigned int定義されています。2の補数での表現は標準では義務付けられていませんが、符号なしに変換するアルゴリズムは次のとおりです。「値が範囲内になるまで、newtypeで表現できる最大値より1つ多い値を繰り返し加算または減算することにより、値が変換されます。ニュータイプの」
パスカルキュオック2010

1
@Pascal:C99を参照しているようですが、質問にはC ++のタグが付けられています。
Georg Fritzsche 2010

回答:


67

公式の回答について-セクション4.7conv.integral

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

これは基本的に、基礎となるアーキテクチャが2の補数ではないメソッド(符号付きの大きさや1の補数など)に格納されている場合、符号なしへの変換は2の補数であるかのように動作する必要があることを意味します。


37
何をして整数のソースに少なくとも符号なし整数の合同を意味ですか?
デビッド・ロドリゲス-ドリビアス2013

11
@例としてDavidRodríguez-dribeas、5および3は両方とも1であり、5%2および3%2は"合同MOD 2"である
JoeQuery

どのバージョンのC ++標準に関連していますか?すべて?
AlexeyKruglov20年

36

-5(2の補数)を表すビットパターンをunsignedintに割り当てます。これは大きな符号なしの値になります。32ビットintの場合、これは2 ^ 32-5または4294967291になります。


2
ビットはそれとは何の関係もありません。
GManNickG 2010

1
@BenVoigt:十分に公平です。つまり、ビットの解釈方法とは何の関係もありません。(つまり、引用部分の「ビット」は単に省略形ですceil(log_2(x))。)
GManNickG 2012年

1
@GManNickGビット(のように、ビットに属します)?2の補数(それはあなたにとってとてもいいことです)?GAAAAAAAAAAAAAH!
NullUserException 2012年

1
@NullUserException:ハハ、わかっています。「* s」の代わりに「* 's」を書くことは、私がしばらくの間持っていたひどい習慣です。補完ではなく褒め言葉に関しては、それは純粋な嘲笑です。:)
GManNickG 2012年

シンプルさが鍵です。この答えはそれを持っています。(2 ^ 32-5)は、ドキュメントを引用するよりもこの動作をよく説明しています。
Redhart 2016年

4

これは、最大符号なし整数-4の値の正の整数として表示されます(値はコンピューターアーキテクチャーとコンパイラーによって異なります)。

ところで
、これは単純なC ++の「helloworld」タイプのプログラムを作成して確認し、自分の目で確かめることができます。


私はそれを書いてチェックしたので、質問をしましたが、コンパイラがどのようにしてその正の値に到達したのかわかりませんでした。ありがとう
ckv 2010

6
残念ながら、C ++では、動作をテストするプログラムを作成することは必ずしも良い考えではありません。たとえば、署名されたオーバーフローの場合に何が起こるかをテストしようとすると、未定義の動作が発生します。これは、すべてのマシン/コンパイラで同じであるとは限りません。
ベンジョーンズ

4

そうです、符号付き整数は2の補数形式で格納され、符号なし整数は符号なしバイナリ表現で格納されます。C(およびC ++)は2つを区別しないため、最終的に得られる値は、2の補数のバイナリ表現の符号なしバイナリ値にすぎません。


16
2の補数に格納されない場合があります。
GManNickG 2010

何かが「2に格納されている」とはどういう意味ですか?@GManNickG
JeremyF

4
@JeremyF:「2の補数」ではなく「2の補数」。これはGoogleで使用可能な用語であり、符号付き整数を表す方法です。
GManNickG 2014

2

はい、その通りです。割り当てられる実際の値は、3番目を除くすべてのビットセットのようなものです。-1はすべてのビットが設定され(16進数:0xFFFFFFFF)、-2は最初のビットを除くすべてのビットです。表示されるのは、おそらく16進値0xFFFFFFFBで、10進数で4294967291に対応します。


3
ビットはそれとは何の関係もありません。整数表現は指定されていません。
GManNickG 2010

2
あなたの答えは正しく、厳格で、私がクラスで決して使用しないようなものです。
マーティン

-5の2の補数については私の答えを参照してください。ここでバイナリ値に対して正しく計算したとは思いません。
cynistersix 2011

0

符号なし変数に負の値を割り当てると、2の補数法を使用して処理します。この方法では、すべての0を1に、すべての1を0に反転してから、1を加算します。あなたの場合、4バイト(32ビット)のintを扱っているので、32ビット数で2の補数法を使用しようとします。これにより、上位ビットが反転します。例えば:

┌─[student@pc]─[~]
└──╼ $pcalc 0y00000000000000000000000000000101      # 5 in binary
        5                       0x5                     0y101
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010      # flip all bits  
      4294967290      0xfffffffa      0y11111111111111111111111111111010
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 + 1  # add 1 to that flipped binarry
      4294967291      0xfffffffb      0y11111111111111111111111111111011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.