16

これは、プログラミングの問題ではなく、言語設計の問題です。

以下は、 JLS 15.19 Shift Operatorsからの抜粋です。

左側のオペランドの昇格された型が の場合、int右側のオペランドの下位 5 ビットのみがシフト距離として使用されます。

左側のオペランドの昇格された型が の場合、long右側のオペランドの下位 6 ビットのみがシフト距離として使用されます。

この動作はC# でも指定されており、Javascript の公式仕様 (存在する場合) に含まれているかどうかはわかりませんが、少なくとも私自身のテストに基づいても当てはまります。

その結果、次のことが成り立ちます。

(1 << 32) == 1

この仕様は、基盤となるハードウェアが 32 ビット値をシフトするときにカウント オペランドに 5 ビット (および 64 ビットの場合は 6 ビット) しか使用しないという事実におそらく「触発された」ものであることを理解しています。たとえば、JVM レベルですが、C# や Java などの高レベル言語がこの低レベルの動作を維持するのはなぜでしょうか? ハードウェアの実装を超えた抽象的なビューを提供し、より直感的に動作するべきではないでしょうか? (他の方向にシフトすることを意味する負の数を取ることができればさらに良いです!)

4

3 に答える 3

8

Java と C# は完全に「ハイレベル」ではありません。彼らは、マイクロベンチマークで輝くために、効率的なコードにコンパイルできるようになるために一生懸命努力しています。intこれが、デフォルトの整数型として、それ自体がオブジェクトであり、固定範囲に限定されない真の整数を持つ代わりに、「値型」を持っている理由です。

したがって、それらはハードウェアが行うことを模倣します。彼らはマスキングを義務付けているという点で、それを少しトリミングしていますが、C はそれを許可するだけです。それでも、Java と C# は「中レベル」の言語です。

于 2010-02-22T14:41:41.160 に答える
5

C# と Java では、sparc と x86 の両方のシフト命令が行うことと同じように、シフト カウントの下位ビットのみを使用するものとしてシフトを定義しています。Java はもともと Sun によって sparc プロセッサに実装され、C# は Microsoft によって x86 に実装されました。

対照的に、C/C++ は、シフト カウントが 0..31 の範囲 (32 ビット int の場合) にない場合、シフト命令の動作を未定義のままにし、任意の動作を許可します。これは、C が最初に実装されたとき、ハンドウェアによってこれらの処理が異なっていたためです。たとえば、VAX では、負の量だけシフトすると反対方向にシフトします。したがって、C では、コンパイラはハードウェア シフト命令を使用するだけで、それが行うことは何でも実行できます。

于 2010-02-22T18:36:04.380 に答える
5

ほとんどのプログラミング環境では、整数は 32 ビットしかないためです。したがって、整数全体をシフトするには 5 ビット (32 個の値を表すのに十分) で十分です。64 ビットの長さについても同様の理由があります。値全体を完全にシフトするには、6 ビットで十分です。

混乱の一部は理解できます。右側のオペランドが 32 より大きい値になる計算の結果である場合、マスクを適用するのではなく、すべてのビットをシフトするだけであると考えるかもしれません。

于 2010-02-22T14:40:17.033 に答える