Вероятно, ЦП на самом деле вычисляет
a >> (b % 32)
в foo
; между тем, 1 >> 32 является константным выражением, поэтому компилятор сворачивает константу во время компиляции, что так или иначе дает 0.
Поскольку стандарт (C ++ 98 и раздел 5.8 / 1) гласит, что
Поведение не определено , если правый операнд отрицательный или больше или равен длине в битах повышенного левого операнда.
Нет противоречия, если foo(1,32)
и 1>>32
дают разные результаты.
С другой стороны, в bar
вы указали 64-битное значение без знака, так как 64> 32 гарантирует, что результат должен быть 1/2 32 = 0 Тем не менее, если вы напишите
bar(1, 64);
вы все равно можете получить 1.
Редактировать: логический сдвиг вправо (SHR) ведет себя как a >> (b % 32/64)
на x86 / x86-64 (Intel # 253667, стр. 4-404):
Операндом-адресатом может быть регистр или ячейка памяти. Операндом count может быть непосредственное значение или регистр CL. Счет замаскирован до 5 бит (или 6 бит, если в 64-битном режиме используется REX.W). Диапазон счетчиков ограничен от 0 до 31 (или 63, если в 64-битном режиме и REX .W используется). Для счетчика 1 предусмотрена специальная кодировка кода операции.
Однако в ARM (как минимум, armv6 и 7) логический сдвиг вправо (LSR) реализован как (ARMISA Страница A2-6)
(bits(N), bit) LSR_C(bits(N) x, integer shift)
assert shift > 0;
extended_x = ZeroExtend(x, shift+N);
result = extended_x<shift+N-1:shift>;
carry_out = extended_x<shift-1>;
return (result, carry_out);
где (ARMISA Page AppxB-13)
ZeroExtend(x,i) = Replicate('0', i-Len(x)) : x
Это гарантирует, что смещение вправо ≥32 приведет к нулю. Например, когда этот код запускается на iPhone, foo(1,32)
выдаст 0.
Это показывает, что сдвиг 32-разрядного целого числа на ≥32 непереносим.