& выполняет побитовое преобразование и операцию между двумя значениями. Если одно из значений является константой и имеет некоторые полезные свойства.
A | B | A & B
---+---+-------
0 | 0 | 0
0 | 1 | 0
---+---+-------
1 | 0 | 0
1 | 1 | 1
Как видно из таблицы истинности, первые две строки показывают, что если A = 0, A & B = 0. Таким образом, установка нуля в маске в некоторой позиции приводит к очистке этот бит
Последние две строки показывают, что если A = 1, A & B = B. Таким образом, помещение единицы в маску в некоторой позиции приводит к тому, что пропускает этот бит.
Таким образом, вы можете использовать постоянную маску для очистки битов за пределами известного поля.
Вы можете выполнить то же упражнение с OR (|) и XOR (^) и заключить, что маска для использования с | устанавливает биты значения, где маска равна 1. ^ имеет эффект переключения битов значения, где маска равна 1.
/ * в ответ на комментарий * /
Это не показатель степени бит это поле экспоненты длиной 8 битов. Итак, если вы строите свою маску следующим образом:
0111 1111 1000 0000 0000 0000 0000 0000 (mask === 0x7F800000)
1011 1010 0101 0110 0110 1010 1001 1010 (value)
-------------------------------------------------
0011 1010 0000 0000 0000 0000 0000 0000 (result)
Здесь вы можете видеть, что все, что осталось от этой операции, это биты, составляющие поле экспоненты (а именно 01110100). Теперь, если вы хотите узнать значение поля, вам необходимо сместить результат вправо на требуемую величину. Требуемым количеством является (в общем случае) позиция с нулевым индексом младшего значащего бита поля. Для поля экспоненты необходимая величина сдвига составляет 23.
На боковой ноте вы должны быть осторожны при переходе вправо. Здесь мы можем избежать неприятностей, потому что знаем, что наша маска имеет ноль в старшем значащем бите, но если бы это было не так, было бы разумно привести наш результат к значению без знака перед смещением вправо. Если вы не получите расширение знака.
int8_t exponent = ((uint32_t) (value & 0x7F800000)) >> 23;
// the cast is not necessary in this case because the mask has a 0 in the msb
Если вы хотите извлечь знаковый бит, этот бросок станет важным:
int8_t sign = ((uint32_t) (value & 0x80000000)) >> 31;
(я не знаю, откуда у вас представление, что вам придется сдвинуться на 8, чтобы извлечь бит знака)