Я думаю, что схожу с ума от этого.
У меня есть фрагмент кода, который должен создать (беззнаковое) целое число с N
последовательными битами, установленными в 1. Точнее, у меня естьбитовую маску, и в некоторых ситуациях я хотел бы установить ее для сплошного rnage.
У меня есть следующая функция:
void MaskAddRange(UINT& mask, UINT first, UINT count)
{
mask |= ((1 << count) - 1) << first;
}
Простыми словами: 1 << count
в двоичном представлении100...000
(число нулей равно count
), вычитая 1 из такого числа, получаем 011...111
, а затем мы просто сдвигаем его влево на first
.
Вышеприведенное должно дать правильный результат,когда соблюдается следующее очевидное ограничение:
first + count <= sizeof(UINT)*8 = 32
Обратите внимание , что оно должно также корректно работать в «экстремальных» случаях.
- если
count = 0
, у нас есть (1 << count) = 1
, и, следовательно, ((1 << count) - 1) = 0
. - , если
count = 32
, у нас есть (1 << count) = 0
, так как старший бит переполняется, и в соответствии сПравила C / C ++ для операций побитового сдвига не циклические .Затем ((1 << count) - 1) = -1
(все биты установлены).
Однако, как оказалось, для count = 32
формула не работает должным образом.Как обнаружилось:
UINT n = 32;
UINT x = 1 << n;
// the value of x is 1
Более того, я использую MSVC2005 IDE.Когда я вычисляю вышеприведенное выражение в отладчике, результат равен 0. Однако когда я перешагиваю через вышеприведенную строку, x
получает значение 1. При просмотре через дизассемблер мы видим следующее:
mov eax,1
mov ecx,dword ptr [ebp-0Ch] // ecx = n
shl eax,cl // eax <<= LOBYTE(ecx)
mov dword ptr [ebp-18h],eax // n = ecx
В этом нет никакой магии, компилятор просто использовал shl
инструкцию.Тогда кажется, что shl
не делает то, что ожидал.Либо ЦП решает игнорировать эту инструкцию, либо сдвиг обрабатывается по модулю 32, или не знаю.
Мои вопросы:
- Какое правильное поведение
shl
/ shr
инструкции? - Есть ли флаг CPU, управляющий инструкциями по сдвигу битов?
- Соответствует ли это стандарту C / C ++?
Заранее спасибо
Редактировать:
Спасибо за ответы.Я понял, что (1) shl
/ shr
действительно обрабатывает операнд по модулю 32 (или & 0x1F) и (2) стандарт C / C ++ рассматривает сдвиг более чем на 31 бит как неопределенное поведение.
Тогда у меня есть еще один вопрос.Как я могу переписать свое «маскирующее» выражение, чтобы охватить и этот крайний случай.Должно быть без разветвления (if
, ?
).Какое самое простое выражение?