web-dev-qa-db-ja.com

右シフトと符号付き整数

私のコンパイラでは、次の擬似コード(値がバイナリに置き換えられています):

sint32 Word = (10000000 00000000 00000000 00000000);
Word >>= 16;

次のようなビットフィールドを持つWordを生成します。

(11111111 11111111 10000000 00000000)

私の質問は、すべてのプラットフォームとC++コンパイラでこの動作に依存できますか?

21
Anne Quinn

次のリンクから:
INT34-C。負のビット数またはオペランドに存在するビット数以上で式をシフトしないでください

非準拠のコード例(右シフト)
E1 >> E2の結果は、E1右シフトされたE2ビット位置です。 E1に符号なしの型がある場合、またはE1に符号付きの型と非負の値がある場合、結果の値はE1/2の商の整数部分になります。E2E1に符号付きの型と負の値がある場合、結果の値は実装で定義され、算術(符号付き)シフトのいずれかになります。
Arithmetic (signed) shift
または論理(符号なし)シフト:
Logical (unsigned) shift
この非準拠のコード例は、右のオペランドがプロモートされた左のオペランドの幅以上であるかどうかのテストに失敗し、未定義の動作を許可します。

unsigned int ui1;
unsigned int ui2;
unsigned int uresult;

/* Initialize ui1 and ui2 */

uresult = ui1 >> ui2;

右シフトが算術(符号付き)シフトとして実装されているのか、論理的(符号なし)シフトとして実装されているのかを推測することも、脆弱性につながる可能性があります。推奨事項を参照してください INT13-C。符号なしオペランドでのみビット演算子を使用してください

23
Andrew Clark

いいえ、この動作に依存することはできません。負の量の右シフト(あなたの例が扱っていると思います)は実装で定義されています。

13

C++ではありません。実装やプラットフォームに依存します。

他のいくつかの言語では、はい。たとえば、Javaでは、>>演算子は、常に左端のビットを使用して入力するように正確に定義されています(これにより、符号が保持されます)。 >>>演算子は0を使用して入力します。したがって、信頼できる動作が必要な場合、考えられるオプションの1つは、別の言語に変更することです。 (明らかに、これは状況によってはオプションではない場合があります。)

6
Keith Irwin

AFAIK整数は、C++では符号の大きさとして表すことができます。その場合、符号拡張は0で埋められます。したがって、これに依存することはできません。

3
CodesInChaos

最新のC++ 20ドラフト から:

符号付き整数型の右シフトは、符号拡張を実行する算術右シフトです。

1
Lyberta