Как работает возврат битов в байте?
Я новичок в программировании, и я нашел этот метод для обращения битов в байте в C:
//(10000011) -> (11000001)
unsigned char reverse(unsigned char b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
опубликовано пользователем в ответ на этот вопрос, но я не могу понять, как это работает. Что означают эти константы?
5 ответов
Это может помочь посмотреть на двоичное представление вышеуказанных чисел:
0xF0: 11110000
0x0F: 00001111
0xCC: 11001100
0x33: 00110011
0xAA: 10101010
0x55: 01010101
Первая пара чисел используется, чтобы замаскировать и поменять местами первые 4 бита и последние 4 бита байта.
Вторая пара маскирует и заменяет первые 2 бита и последние 2 бита из набора из 4 битов.
Третья пара маскирует и заменяет соседние пары битов.
Код сначала меняет местами "полубайты", то есть старшие 4 бита с младшими 4 битами. Затем он меняет две пары высшего порядка вместе и нижние пары вместе; наконец, он выполняет парные перестановки 2n и 2n+1 бит.
Я собираюсь обозначить биты первоначального значения b
здесь по их показателю в угловых скобках (это просто псевдо-запись, которую я здесь использую, а не C); я использую o
отмечать любой бит, который всегда равен 0. Итак, в начале мы имеем
<76543210>
Нет в первой операции у нас
<76543210> & 0xF0
-><7654oooo>
<76543210> & 0x0F
-><oooo3210>
Теперь первое смещено вправо на 4 бита, а второе влево на 4, таким образом, мы получаем
<7654oooo> >> 4
-><oooo7654>
<oooo3210> << 4
-><3210oooo>
Наконец они объединяются, и, следовательно, после утверждения
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
значение b
это перестановка <32107654>
оригинальных битов.
Во втором утверждении маска 0xCC
является 11001100
в двоичном виде, и 0x33
является 00110011
в двоичном формате; промежуточные значения:
(<32107654> & 0xCC) >> 2
-><32oo76oo> >> 2
-><oo32oo76>
; а также(<32107654> & 0x33) << 2
-><oo10oo54> << 2
-><10oo54oo>
,
Эти 2 or'ed вместе приведут к перестановке <10325476>
, Теперь, наконец, маска 0xAA
является 10101010
в двоичном виде, и 0x55
является 01010101
, Таким образом, мы имеем
(<10325476> & 0xAA) >> 1
-><1o3o5o7o> >> 1
-><o1o3o5o7>
; а также(<10325476> & 0x55) << 1
-><o0o2o4o6> << 1
-><0o2o4o6o>
Эти or'ed вместе приведут к перестановке <01234567>
что является противоположностью оригинала.
Так что это просто немного сдвигается. Биты расположены в следующем порядке:
76543210
Теперь, первая строка, первая часть сохраняет старшие биты, устанавливает младшие биты в 0 (маска 0b11110000), сдвигает их на 4 вправо. Вторая часть делает то же самое для младших битов (маска 0b00001111) и смещается влево:
first line, first part: 7654xxxx => xxxx7654 (bits shift to the right)
first line, second part: xxxx3210 => 3210xxxx (bits shift to the left)
add them together: => 32107654
Затем вторая строка. То же действие, разные маски (0b11001100 и 0b00110011 соответственно), с 32107654
:
second line, first part: 32xx76xx => xx32xx76 (bits shift to the right)
second line, second part: xx10xx54 => 10xx54xx (bits shift to the left)
add them together: => 10325476
Третья строка совпадает с другими масками (0b10101010 и 0b01010101 соответственно), с 10325476
:
third line, first part: 1x3x5x7x => x1x3x5x7 (bits shift to the right)
third line, second part: x0x2x4x6 => 0x2x4x6x (bits shift to the left)
add them together: => 01234567
Итак, мы в конечном итоге, с действием:
76543210 => 01234567
Вам нужно понять 4 основных момента, чтобы понять, что означает приведенный выше код.
& (AND) Bitwise Operator.
| (OR) Bitwise Operator.
>> (Right Shift Operator).
<< (Left Shift Operator).
К счастью, я только что написал подробный блог, который объясняет все о системе счисления и манипулировании битами
Давайте нумеруем биты в b
следующее:
01234567
0xF0
в двоичном есть 11110000
, а также 0x0F
является 00001111
, Первое назначение сдвигает самые левые 4 бита вправо, а самые правые 4 бита влево, а затем объединяет их с OR
Итак, результат:
45670123
0xCC
является 11001100
, а также 0x33
является 00110011
, Когда эти маскированные биты сдвинуты на 2 бита и объединены, результатом является:
67452301
В заключение, 0xAA
является 10101010
а также 0x55
является 01010101
, Когда эти маски и смены сделаны, результат:
76543210
Вуаля! это обратный порядок.
Обратите внимание, что для каждой пары сдвигов битовые маски являются инверсиями друг друга, и количество сдвигаемых битов совпадает с длиной последовательностей в 1 бит в маске. Таким образом, каждый из них меняет группы битов, размер которых равен длине последовательности.