次のコードを検討してください。
UInt32 val = 1;
UInt32 shift31 = val << 31; // shift31 == 0x80000000
UInt32 shift32 = val << 32; // shift32 == 0x00000001
UInt32 shift33 = val << 33; // shift33 == 0x00000002
UInt32 shift33a = (UInt32)((UInt64)val << 33); // shift33a == 0x00000000
(32 より大きいシフトの使用に関する) 警告は生成されないため、予期される動作である必要があります。
生成されたアセンブリに実際に出力されるコード (または少なくとも Reflector によるコードの解釈) は次のとおりです。
uint val = 1;
uint shift31 = val << 0x1f;
uint shift32 = val;
uint shift33 = val << 1;
uint shift33a = val << 0x21;
IL (ここでも Reflector を使用) は
L_0000: nop
L_0001: ldc.i4.1
L_0002: stloc.0
L_0003: ldloc.0
L_0004: ldc.i4.s 0x1f
L_0006: shl
L_0007: stloc.1
L_0008: ldloc.0
L_0009: stloc.2
L_000a: ldloc.0
L_000b: ldc.i4.1
L_000c: shl
L_000d: stloc.3
L_000e: ldloc.0
L_000f: conv.u8
L_0010: ldc.i4.s 0x21
L_0012: shl
L_0013: conv.u4
L_0014: stloc.s shift33a
何が起こっているのか理解しています ( MSDNで説明されています)。コードがコンパイルされると、32 ビット値をシフトするときに下位 5 ビットのみが使用されます...なぜこれが起こるのか知りたいです。
(shift33a
出てくる方法は、ILのc#プレゼンテーションが別のものにコンパイルされるため、Reflectorで何かが正しくないと私に思わせます)
質問):
- 「シフトする値」の下位 5 ビットのみが使用されるのはなぜですか ?
- 「31 ビットを超えてシフトしても意味がない」場合、警告がないのはなぜですか?
- これは下位互換性の問題ですか (つまり、これはプログラマーが「期待」するものですか)?
- 基礎となる IL は 31 ビットを超えるシフトを行うことができますが (のように
L_0010: ldc.i4.s 0x21
)、コンパイラが値をトリミングしているというのは正しいですか?