web-dev-qa-db-ja.com

Cでintをshortに変換する

私が持っています:

int a = 2147483647;
short b = (short)a;

b = -1int32short)に変換されることを期待しながら、int16を取得します。いくつかの値とnot-1が表示されることを期待しています。

これを手伝ってください。

9
user1128265

Int Aはshortのサイズよりも大きいです。 Aをshortに変換すると、左端のビットが1になり、負の数であることを示します。 -1を取得しているので、16ビットすべてで1を取得していると思います。これにより、-2 ^ 15 + 2 ^ 14 + 2 ^ 13 ... + 2 ^ 0が得られます。 -1。要するに(意図的なしゃれはありません)、整数が大きすぎる場合、整数をshortに変換することはできません。

6
Magn3s1um

値2147483647、または231-1は16ビット整数をオーバーフローします。そのバイナリ表現は、MSBではゼロで、残りのビットでは31が続きます。

実装では、最後の16ビットがshortへの変換に使用されているようです。これが発生すると、それらすべてが1に設定され、-12の補数 表現になります。

32-bit int:   01111111111111111111111111111111
16-bit short: ----------------1111111111111111

ただし、2補数表現もこの動作も一般にC++標準の一部ではないため、この動作は実装定義です。

23
dasblinkenlight

値をsigned型に変換し、ソース値がターゲット型に適合しない場合、を生成します実装定義結果。つまり、準拠するコンパイラのドキュメントは、その結果が何であるかを文書化する必要があります。

(これは、算術演算子のオーバーフロー時の動作とは異なります。例:

int overflow = INT_MAX + 1;

実際には未定義の動作があります。ただし、どちらの場合も、この種の問題を引き起こさないようにコードを書くように注意してください。)

多くの実装では、変換と算術の両方で、ターゲットがNビット型であるオーバーフローは、正しい結果の下位Nビットを単純に受け取ります。

あなたの場合、intは明らかに32ビットで、shortは16ビットです(これらのサイズは実装によって異なる場合があります)。 21474836470x7fffffffであり、下位16ビットは0xffffであり、これも(実装では)タイプshort-1の表現です。 。

符号なし型への変換の場合、結果は規格によって厳密に定義されています。結果の下位Nビットを取ります。また、浮動小数点変換のオーバーフロー(たとえば、非常に大きなdouble値をfloatに変換する)の場合、動作は未定義です。

これまでのところ、これはCとC++ですべて同じです。しかし、混乱を増すために、1999年の標準以降、実装定義の信号を発生させるためにオーバーフローした符号付き変換が許可されています。 C++にはありません。実際にこれを行うコンパイラーについては知りません。

何らかの値とnot-1が表示されることを期待しています。

-1is「一部の値」。期待していた具体的な価値はありましたか?

ちなみに:

short b = (short)a;

キャストは不要です。割り当て、初期化、パラメーターの受け渡し、およびreturnステートメントは、キャストなしで任意の数値タイプ間で値を割り当てることができます。値は暗黙的に変換されます。

short b = a;
11
Keith Thompson

これはimplementation definedの動作です。たとえば、gccIntegers Implementation document と言います。

幅Nの型への変換の場合、値は2 ^ Nを法として、型の範囲内になるように縮小されます。シグナルは発生しません。

これはコンパイラごとに異なる可能性があります。clangvisual studioも同様のドキュメントを掘り下げることはできません。

C++標準草案のセクション4.7 Integral conversions段落3

宛先タイプが署名されている場合、宛先タイプ(およびビットフィールド幅)で表すことができる場合、値は変更されません。それ以外の場合、値は実装定義です

これがunsignedの場合、段落2のように、完全に適切に定義された動作があります。

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

言語は、C99ドラフト標準セクション6.3.1.3 Signed and unsigned integersで類似しています。

8
Shafik Yaghmour

あなたはこれを行うことができます:

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

4
edW