Рассмотрим следующий код:
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 (опять же, используя 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); когда код скомпилирован, используются только младшие 5 бит при смещении 32-битного значения... Мне любопытно, как это сделать почему.
(Вывод shift33a
также заставляет меня думать, что с Reflector что-то не совсем верно, так как их С# -презентация IL будет компилироваться на что-то другое)
Вопрос (ы):
- Почему являются только более низкими 5 битами значения "значение для переключения"?
- Если "не имеет смысла сдвигать более 31 бит", почему нет предупреждений?
- Является ли это обратной совместимостью (т.е. как программисты "ожидают" )?
- Правильно ли, что базовый IL может выполнять сдвиги более 31 бит (как в
L_0010: ldc.i4.s 0x21
), но компилятор обрезает значения?