67

算術ビット シフト演算子が C でどのように機能するか、およびそれが符号付き 32 ビット整数にどのように影響するかを理解しようとしています。

簡単にするために、1 バイト (8 ビット) 内で作業するとしましょう。

x = 1101.0101
MSB[ 1101.0101 ]LSB

Stack Overflow といくつかの Web サイトに関する他の投稿を読んで、次のことがわかりました: <<MSB に向かって (私の場合は左に) シフトし、「空の」LSB ビットを 0 で埋めます。

そして>>、LSBに向かって(私の場合は右に)シフトし、「空の」ビットをMSビットで埋めます

そのx = x << 7ため、LSB を MSB に移動し、すべてを 0 に設定します。

1000.0000

>> 7さて、最後の結果が だとしましょう。これにより、[0000.0010]? 私は正しいですか?

シフト演算子に関する私の仮定は正しいですか?

私は自分のマシンでテストしました**

int x = 1;   //000000000......01

x = x << 31; //100000000......00

x = x >> 31; //111111111......11 (Everything is filled with 1s !!!!!) 

なんで?

4

6 に答える 6

69

負の符号付き数値の右シフトには、実装定義の動作があります。

8ビットが符号付き8ビット値を表すことを意図している場合(8ビットの例に切り替える前に「符号付き32ビット整数」について話しているため)、負の数になります。右にシフトすると、プラットフォームやコンパイラに応じて、「空の」ビットが元の MSB で埋められる (つまり、符号拡張が実行される) か、0 にシフトされる場合があります。

(実装定義の動作とは、コンパイラが適切な処理を実行することを意味しますが、プラットフォームに依存する方法で行われます。コンパイラのドキュメントには、その内容が記載されているはずです。)


左シフトは、数値が負で始まる場合、またはシフト操作が 1 を符号ビットまたはそれを超えてシフトする場合、未定義の動作をします (オーバーフローを引き起こす符号付き値に対するほとんどの操作と同様)。

(未定義の動作とは、何かが起こる可能性があることを意味します。)


どちらの場合も、符号なし値に対する同じ操作が明確に定義されています。「空の」ビットは 0 で埋められます。

于 2010-10-24T19:11:05.853 に答える
42

ビット単位のシフト演算は負の値に対して定義されていません

「<<」の場合

6.5.7/4 [...] E1 に符号付きの型と非負の値があり、E1×2 E2が結果の型で表現できる場合、それが結果の値です。それ以外の場合、動作は未定義です。

および '>>' の場合

6.5.7/5 [...] E1 に符号付きの型と負の値がある場合、結果の値は実装定義です。

特定の実装での符号付き数値に対するこれらの操作の動作を調べるのは時間の無駄です。他の実装でも同じように動作するという保証がないためです (たとえば、実装とは、コンピューター上で特定のコマンドライン パラメータ)。

まったく同じコンパイラの古いバージョンまたは新しいバージョンでも機能しない場合があります。コンパイラは、これらのビットをランダムまたは未定義として定義することさえあります。これは、まったく同じコード シーケンスが、ソース全体で使用された場合、またはアセンブリの最適化やその他のレジスタの使用などに依存する場合でも、まったく異なる結果を生成する可能性があることを意味します。関数にカプセル化されている場合、同じ引数を使用した 2 つの連続した呼び出しで、これらのビットに同じ結果が生成されないことさえあります。

負でない値のみを考慮すると、左に 1 シフトする効果 ( expression << 1) は式を 2 倍するのと同じであり (式 * 2 がオーバーフローしない場合)、右に 1 シフトする効果 ( expression >> 1) は で除算するのと同じです。 2.

于 2010-10-24T19:17:48.273 に答える
6

他の人が言ったように、負の値のシフトは実装によって定義されます。

ほとんどの実装では、符号ビットを使用してシフトインビットを埋めることにより、符号付き右シフトをfloor(x / 2 N )として扱います。この操作は非常に一般的であるため、実際には非常に便利です。一方、符号なし整数を右にシフトする場合、ビット単位でシフトするとゼロになります。

マシン側から見ると、ほとんどの実装には2種類の右シフト命令があります。

  1. 私が説明したように機能する「算術」右シフト(多くの場合、ニーモニックASRまたはSRAがあります)。

  2. 期待どおりに機能する「論理」右シフト(ニーモニックLSRまたはSRLまたはSRを持つことが多い)。

ほとんどのコンパイラは、最初に符号付き型に使用し、次に符号なし型に使用します。便宜上。

于 2010-10-24T22:32:54.493 に答える