考虑以下代码:
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的移位),因此它必须是预期的行为。
实际输出到生成的程序集(或至少是反射器对代码的解释)的代码是
uint val = 1;
uint shift31 = val << 0x1f;
uint shift32 = val;
uint shift33 = val << 1;
uint shift33a = val << 0x21;
IL(再次使用反射器)为
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#表示将编译成不同的东西)
问题:
-
为什么?
是否仅使用“移位值”的低位5位?
-
如果“移位超过31位没有意义”,为什么没有警告?
-
这是向后兼容的事情吗(即,这是程序员“期望”发生的事情)?
-
底层IL可以进行超过31位的移位(如
L_0010: ldc.i4.s 0x21
)但是编译器正在修剪这些值?