2017-10-13 8 views
0

を切り捨てるためにどのように私は、同様の質問をしてきましたが、より多くの研究の後、私は理解できない何かに出くわした、とうまくいけば、誰かがこの動作を引き起こしているかを説明することができます正しく整数型

// We wish to store a integral type, in this case 2 bytes long. 
signed short Short = -390; 

// In this case, signed short is required to be 2 bytes: 
assert(sizeof(Short) == 2); 

cout << "Short: " << Short << endl; // output: -390 

signed long long Long = Short; 

// in this case, signed long long is required to be 8 bytes long 
assert(sizeof(Long) == 8); 

cout << "Long: " << Long << endl; // output: -390 

// enough bytes to store the signed short: 
unsigned char Bytes[sizeof(Short)]; 

// Store Long in the byte array: 
for (unsigned int i = 0; i < sizeof(Short); ++i) 
    Bytes[i] = (Long >> (i * 8)) & 0xff; 

// Read the value from the byte array: 
signed long long Long2 = (Bytes[0] << 0) + (Bytes[1] << 8); 

cout << Long2 << endl; // output: 65146 

signed short Short2 = static_cast<signed short>(Long2); 

cout << Short2 << endl; // output: -390 

は出力:

-390 
-390 
65146 
-390 

誰かがここで何が起こっているのか説明できますか?これは未定義の動作ですか?どうして?

+0

正式には、実装の詳細である整数の正確な表現に依存しているため、プログラムの動作は明示されていません(おそらくは未定義です)。実際には、典型的な2の補数表現を仮定すると、あなたは符号拡張を失っています: 'Long2'は、' Long'が '0xFF'を持つ上位バイトでゼロを持っています –

+0

@IgorTandetnikこうして整数を格納する理由は、私はどこかでそれを安全に行う方法を読んでいます。ソースは素晴らしくなかったと思いますか?整数をバイト配列に適切に格納する方法を詳しく説明できますか?または自分のフォーマットを定義する必要がありますか? –

+0

「Long >> 8」は、「Long」が負で、実装定義の振る舞いです。 – aschepler

答えて

1

負の数値が格納される方法と関係があります。負の数はバイナリ形式で1で始まります。

signed long long Long = Short; 

これは自動的に変換を行います。 1つのビットからもう1つのビットにビットを割り当てるだけではなく、1で始まる64ビットの値が負の値に変換され、残りのビットが2の補数で表されます(全部働くことはできませんビットが出ている)。

signed long long Long2 = (Bytes[0] << 0) + (Bytes[1] << 8); 

ここでは、2つの最後のバイトのみを取得しています。これは390マグニチュードを表します。最初の2バイトはゼロになるので、正の数だと考えます。それは2^16 - 390として機能するはずです。

signed short Short2 = static_cast<signed short>(Long2); 

これはオーバーフローです。 65146は符号付き2バイト整数に収まらないため、符号ビットの入力が終了し、負と解釈されます。同時発生がないことにより、それが表す負の数は-390である。

+0

これは説明に感謝します。 –

関連する問題