Я довольно новичок в программировании на C и столкнулся с битовой маскировкой. Может ли кто-нибудь объяснить мне общую концепцию и функцию битовой маскировки? Примеры очень ценятся.
Я довольно новичок в программировании на C и столкнулся с битовой маскировкой. Может ли кто-нибудь объяснить мне общую концепцию и функцию битовой маскировки? Примеры очень ценятся.
Ответы:
Маска определяет, какие биты вы хотите сохранить и какие биты вы хотите очистить.
Маскировка - это применение маски к значению. Это достигается путем:
Ниже приведен пример извлечения подмножества битов в значении:
Mask: 00001111b
Value: 01010101b
Применение маски к значению означает, что мы хотим очистить первые (старшие) 4 бита и оставить последние (младшие) 4 бита. Таким образом мы извлекли младшие 4 бита. Результат:
Mask: 00001111b
Value: 01010101b
Result: 00000101b
Маскирование реализовано с использованием AND, поэтому в C мы получаем:
uint8_t stuff(...) {
uint8_t mask = 0x0f; // 00001111b
uint8_t value = 0x55; // 01010101b
return mask & value;
}
Вот довольно распространенный вариант использования: извлечение отдельных байтов из более крупного слова. Мы определяем старшие биты в слове как первый байт. Мы используем два оператора для этого &
, и >>
(сдвиг вправо). Вот как мы можем извлечь четыре байта из 32-разрядного целого числа:
void more_stuff(uint32_t value) { // Example value: 0x01020304
uint32_t byte1 = (value >> 24); // 0x01020304 >> 24 is 0x01 so
// no masking is necessary
uint32_t byte2 = (value >> 16) & 0xff; // 0x01020304 >> 16 is 0x0102 so
// we must mask to get 0x02
uint32_t byte3 = (value >> 8) & 0xff; // 0x01020304 >> 8 is 0x010203 so
// we must mask to get 0x03
uint32_t byte4 = value & 0xff; // here we only mask, no shifting
// is necessary
...
}
Обратите внимание, что вы можете переключать порядок операторов выше, вы можете сначала сделать маску, а затем сдвиг. Результаты одинаковы, но теперь вам придется использовать другую маску:
uint32_t byte3 = (value & 0xff00) >> 8;
&
.
#define MASK 0x000000FF .... my_uint32_t &= ~MASK
.
b
указать двоичный литерал не поддерживается всеми компиляторами, правильно?
Маскировка означает сохранение / изменение / удаление нужной части информации. Давайте посмотрим на операцию маскировки изображения; как эта маскирующая операция удаляет любую вещь, которая не является
Мы делаем операцию И в этом примере. Есть и другие маскирующие операторы - ИЛИ , XOR .
Битовая маскировка означает наложение маски на биты. Вот немного маскировки с AND -
1 1 1 0 1 1 0 1 [input] (&) 0 0 1 1 1 1 0 0 [mask] ------------------------------ 0 0 1 0 1 1 0 0 [output]
Таким образом, 1
остаются только средние 4 бита (поскольку эти биты находятся в этой маске).
Давайте посмотрим это с XOR -
1 1 1 0 1 1 0 1 [input] (^) 0 0 1 1 1 1 0 0 [mask] ------------------------------ 1 1 0 1 0 0 0 1 [output]
Теперь, средние 4 бита перевернуты ( 1
стали 0
, 0
стали 1
).
Таким образом, используя битовую маску, мы можем получить доступ к отдельным битам [ примеры ]. Иногда этот метод также может быть использован для повышения производительности. Возьмите это, например,
bool isOdd(int i) {
return i%2;
}
Эта функция сообщает, является ли целое число нечетным / четным. Мы можем достичь того же результата с большей эффективностью, используя
bool isOdd(int i) {
return i&1;
}
Краткое объяснение : Если младший бит двоичного числа 1
является нечетным; потому что 0
это будет даже. Таким образом, делая и с 1
мы удаляем все остальные биты для наименьшего значащего бита т.е. за исключением:
55 -> 0 0 1 1 0 1 1 1 [input] (&) 1 -> 0 0 0 0 0 0 0 1 [mask] --------------------------------------- 1 <- 0 0 0 0 0 0 0 1 [output]