flags = flags ^MASK;
flags ^= MASK;
Например, пусть flags равно 00001111 и MASK — 10110110. Выражение
flags ^MASK становится
(00001111) ^(10110110) // выражение
Манипулирование битами 637
и после вычисления дает следующий результат:
(10111001) // результат
Все биты, установленные в 1 внутри MASK, приводят к переключению соответствующих битов в flags. Все биты в flags, которые соответствуют битам 0 в MASK, остаются неизмененными.
Случай применения: проверка значения бита
Вы уже видели, как изменять значения битов. Предположим, что вместо этого нужно проверить значение какого-нибудь бита. Например, установлен ли в 1 бит 1 в flags? Простое сравнение flags и MASK здесь не подойдет:
if (flags == MASK)
puts("Совпадает !"); /* не работает */
Даже если бит 1 переменной flags установлен в 1, значение какого-то другого бита в flags может сделать результат сравнения недействительным. Чтобы выполнить сравнение только бита 1 в flags с MASK, необходимо сначала замаскировать остальные биты flags:
if ((flags & MASK) == MASK)
puts("Совпадает!");
Побитовые операции имеют приоритет ниже, чем у операции ==, поэтому выражение flags & MASK должно быть заключено в скобки.
Во избежание неполного охвата информации, битовая маска должна иметь ширину не меньше, чем у маскируемого значения.
побитовые операции сдвига
Теперь давайте взглянем на операции сдвига в языке С. Побитовые операции сдвига сдвигают биты влево или вправо. Для большей наглядности мы здесь также будем применять двоичную запись чисел.
Сдвиг влево:<<
Операция сдвига влево (<<) сдвигает биты значения левого операнда влево на количество позиций, заданное правым операндом. Освобождаемые позиции заполняются 0, а биты, выходящие за пределы значения левого операнда, теряются. В следующем примере каждый бит сдвигается на две позиции влево:
(10001010) << 2 // выражение
(00101000) // результат
Эта операция выдает новое битовое значение, но не изменяет операнды. Для примера предположим, что переменная stonk имеет значение 1. Выражение stonk<<2 дает 4, но значением stonk по-прежнему является 1. Чтобы изменить значение переменной, можно воспользоваться операцией сдвига влево с присваиванием (<<=). Эта операция сдвигает биты переменной влево на количество позиций, указанное в правом операнде. Вот пример:
int stonk = 1;
int onkoo;
onkoo = stonk << 2; /* присваивает 4 переменной onkoo */
stonk <<= 2; /* изменяет значение stonk на 4 */
638 Глава 15
Сдвиг вправо:>>
Операция сдвига вправо (>>) сдвигает биты значения левого операнда вправо на количество позиций, указанное в правом операнде. Биты, которые выходят за правую границу левого операнда, теряются. Для типов без знака освобождаемые слева позиции заполняются 0. Для типов со знаком данных результат зависит от системы. Освобождаемые позиции могут заполняться 0 либо битом знака (самого левого):
(10001010) >> 2 // выражение, значение со знаком
(00100010) // результат в одних системах
(10001010) >> 2 // выражение, значение со знаком
(11100010) // результат в других системах
Для значения без знака результат будет следующим:
(10001010) >> 2 // выражение, значение без знака
(00100010) // результат во всех системах
Каждый бит перемещается на две позиции вправо, а освобождаемые позиции заполняются 0.
Операция сдвига вправо с присваиванием (>>=) сдвигает вправо биты левого операнда на заданное в правом операнде количество позиций, например:
int sweet = 16; int ooosw;
ooosw = sweet >> 3; /* ooosw равно 2, sweet по-прежнему 16 */ sweet >>=3; /* значение sweet изменилось на 2 */
Случай применения: побитовые операции сдвига
Побитовые операции сдвига могут служить удобным и эффективным (в зависимости от оборудования) средством выполнения умножения и деления на степени 2:
number << n Умножает number на 2 в степени n
number >> n Делит number на 2 в степени n, если значение number неотрицательно
Эти операции сдвига аналогичны смещению десятичной точки при умножении или делении на 10.
Операции сдвига могут также использоваться для извлечения групп битов из более крупных конструкций. Предположим, что для представления значений цвета применяется переменная типа unsigned long, причем младший байт содержит интенсивность красной составляющей, следующий байт — интенсивность зеленой составляющей, а третий байт — интенсивность синей составляющей цвета. Пусть необходимо сохранить интенсивность каждой составляющей в собственной переменной типа unsigned char. Для этого можно написать такой код:
#define BYTE_MASK 0xff
unsigned long color = 0x002al62f;
unsigned char blue, green, red;
Читать дальше