私が持っています:
int a = 2147483647;
short b = (short)a;
b = -1
がint32
(short
)に変換されることを期待しながら、int16
を取得します。いくつかの値とnot-1
が表示されることを期待しています。
これを手伝ってください。
Int Aはshortのサイズよりも大きいです。 Aをshortに変換すると、左端のビットが1になり、負の数であることを示します。 -1を取得しているので、16ビットすべてで1を取得していると思います。これにより、-2 ^ 15 + 2 ^ 14 + 2 ^ 13 ... + 2 ^ 0が得られます。 -1。要するに(意図的なしゃれはありません)、整数が大きすぎる場合、整数をshortに変換することはできません。
値2147483647、または231-1は16ビット整数をオーバーフローします。そのバイナリ表現は、MSBではゼロで、残りのビットでは31が続きます。
実装では、最後の16ビットがshort
への変換に使用されているようです。これが発生すると、それらすべてが1
に設定され、-1
の 2の補数 表現になります。
32-bit int: 01111111111111111111111111111111
16-bit short: ----------------1111111111111111
ただし、2補数表現もこの動作も一般にC++標準の一部ではないため、この動作は実装定義です。
値をsigned型に変換し、ソース値がターゲット型に適合しない場合、を生成します実装定義結果。つまり、準拠するコンパイラのドキュメントは、その結果が何であるかを文書化する必要があります。
(これは、算術演算子のオーバーフロー時の動作とは異なります。例:
int overflow = INT_MAX + 1;
実際には未定義の動作があります。ただし、どちらの場合も、この種の問題を引き起こさないようにコードを書くように注意してください。)
多くの実装では、変換と算術の両方で、ターゲットがNビット型であるオーバーフローは、正しい結果の下位Nビットを単純に受け取ります。
あなたの場合、int
は明らかに32ビットで、short
は16ビットです(これらのサイズは実装によって異なる場合があります)。 2147483647
は0x7fffffff
であり、下位16ビットは0xffff
であり、これも(実装では)タイプshort
の-1
の表現です。 。
符号なし型への変換の場合、結果は規格によって厳密に定義されています。結果の下位Nビットを取ります。また、浮動小数点変換のオーバーフロー(たとえば、非常に大きなdouble
値をfloat
に変換する)の場合、動作は未定義です。
これまでのところ、これはCとC++ですべて同じです。しかし、混乱を増すために、1999年の標準以降、実装定義の信号を発生させるためにオーバーフローした符号付き変換が許可されています。 C++にはありません。実際にこれを行うコンパイラーについては知りません。
何らかの値とnot
-1
が表示されることを期待しています。
-1
is「一部の値」。期待していた具体的な価値はありましたか?
ちなみに:
short b = (short)a;
キャストは不要です。割り当て、初期化、パラメーターの受け渡し、およびreturn
ステートメントは、キャストなしで任意の数値タイプ間で値を割り当てることができます。値は暗黙的に変換されます。
short b = a;
これはimplementation defined
の動作です。たとえば、gcc
Integers Implementation document
と言います。
幅Nの型への変換の場合、値は2 ^ Nを法として、型の範囲内になるように縮小されます。シグナルは発生しません。
これはコンパイラごとに異なる可能性があります。clang
もvisual studio
も同様のドキュメントを掘り下げることはできません。
C++標準草案のセクション4.7 Integral conversions
段落3
:
宛先タイプが署名されている場合、宛先タイプ(およびビットフィールド幅)で表すことができる場合、値は変更されません。それ以外の場合、値は実装定義です。
これがunsigned
の場合、段落2
のように、完全に適切に定義された動作があります。
宛先タイプが符号なしの場合、結果の値は、ソース整数に合同な最小の符号なし整数です(2nを法とするnは、符号なしタイプを表すために使用されるビット数です)。 [注:2の補数表現では、この変換は概念的なものであり、ビットパターンに変更はありません(切り捨てがない場合)。 —エンドノート]
言語は、C99
ドラフト標準セクション6.3.1.3 Signed and unsigned integers
で類似しています。
あなたはこれを行うことができます:
uint32_t sum=0xFFFF1234;
uint16_t *p= (uint16_t *) ∑
uint16_t checksum=p[0];
チェックサムは0x1234
。
ここに別の方法があります:
union ToShort
{
uint32_t sum;
uint16_t checksum[2];
} toShort;
toShort.sum=0xFFFF1234;
cout << hex << toShort.checksum[0];
出力は1234
。