Можете ли вы контролировать, какой битовый сдвиг вправо заполнит C? - PullRequest
27 голосов
/ 08 декабря 2011

Насколько я знаю, когда вы используете битовый оператор сдвига влево в C, гарантируется, что свободные биты будут заполнены нулями. Тем не менее, я читал, что смещение вправо зависит от реализации, то есть в некоторых машинах свободные биты будут заполнены нулями, в других - 1.

Я использую правый сдвиг в программе, и действительно моя машина заполняет свободные биты 1 с. Проблема в том, что мне нужно заполнить нулями вместо этого.

Есть ли способ заставить 0 использовать правильные сдвиги?

Одним из решений было бы, после применения правого сдвига, создать маску, подобную 011111111, а затем применить побитовое И, который изменит крайний левый 1, который был вставлен, на 0.

Но это громоздко и тратит время. Если бы был способ указать моей машине заполнять правильные смены 1с, это было бы намного проще.

Спасибо

Ответы [ 3 ]

39 голосов
/ 08 декабря 2011

Приведите число к unsigned и затем сдвиньте.Это заставит 0-заполнить.

17 голосов
/ 08 декабря 2011

Нет, вы не можете.

Сдвиги в типах без знака хорошо определены (при условии, что правый операнд неотрицательный и меньше ширины левого операнда), и они всегда заполняются нулями.

Сдвиги (или любые побитовые операции) для подписанных типов, как правило, не очень хорошая идея. Если левый операнд отрицательный, то << имеет неопределенное поведение, а >> дает результат, определенный реализацией (это означает, что компилятор должен задокументировать, что он делает, но у вас нет способа его контролировать). Для неотрицательных значений типа со знаком результат будет тем, что вы ожидаете - если он не переполняется (если он переполняется, поведение не определено).

Вот что говорит C99 (раздел 6.5.7):

Целочисленные продвижения выполняются для каждого из операндов. Тип В результате получается повышенный левый операнд. Если значение правый операнд отрицательный или больше или равен ширине для повышенного левого операнда поведение не определено.

Результат E1 << <strong>E2 равен E1 со смещением влево E2 бит позиции; освобожденные биты заполнены нулями. Если E1 имеет неподписанный тип, значение результата равно E1 × 2 E2 , уменьшено по модулю еще один чем максимальное значение, представляемое в типе результата. Если E1 имеет тип со знаком и неотрицательное значение, и E1 × 2 E2 представлен в тип результата, то это итоговое значение; в противном случае поведение не определено.

Результат E1 >> E2 равен E1 смещенными вправо E2 битовыми позициями. Если E1 имеет тип без знака или если E1 имеет тип со знаком и неотрицательное значение, значение результата является неотъемлемой частью отношения E1 / 2 E2 . Если E1 имеет тип со знаком и отрицательное значение, результирующее значение определяется реализацией.

5 голосов
/ 08 декабря 2011

Существует две разные операции правого сдвига: арифметическая и логическая.

Логический сдвиг используется с числами без знака в C. Он всегда заполняет старшие биты нулями.Это то, что вам нужно.

Арифметическое смещение используется со знаковыми числами, потому что оно сохраняет знак смещаемого числа.Если число положительное, самый значимый бит будет равен 0 и заполнится нулями.Если число отрицательное, старший значащий бит будет равен 1, поэтому он будет заполняться 1 с.

Обратите внимание, что в Java они фактически используют разные операторы: >> для арифметики, >>> для логического.Это необходимо, потому что у Java нет беззнакового типа.

...