Битовые операции для целочисленных операндов
В языке Си имеются шесть операторов (&, |, ^, ~, >>, <<), которые можно использовать в программе для манипулирования битами в целых числах.
Оператор & (поразрядное «И») выполняет операцию логического умножения отдельных одноименных разрядов двух операндов.
Оператор | (поразрядное «ИЛИ») реализует операцию логического сложения отдельных одноименных битов двух операндов.
Операторы & и |, которые работают с операндами побитно, следует отличать от логических операторов && и ||, которые оценивают каждый операнд целиком, равен он нулю или нет. Например, если переменная Var1 = 1, а переменная Var2 = 4, то результат побитовой операции (Var1 & Var2) будет равен нулю, а логической (Var1 && Var2) будет равен единице.
Оператор ^ (поразрядное исключающее «ИЛИ») реализует сложение по модулю 2 для одноименных разрядов.
Оператор инверсии ~ (поразрядное отрицание) инвертирует все биты переменной.
Операции сдвига перемещают разряды операнда влево (<<) или вправо (>>) на указанное число позиций.
Часто операции сдвига используют для быстрого умножения или деления операнда на степень двойки (2, 4, 8, …). Каждый сдвиг влево на один разряд приводит к умножению операнда на два, а каждый сдвиг вправо – к делению на два.
Рассмотрим более подробно битовые операции и их применение при программировании МК.
Оператор сдвига влево <<
Оператор сдвига влево <<выполняет поразрядный сдвиг числа влево. Его синтаксис:
Var1 = Var2 << Num;
где Var1 и Var2 – целочисленные переменные, а Nun – число разрядов для сдвига.
Двоичное значение переменной Var2 сдвигается влево на указанное количество разрядов Num с заполнением освобождающихся справа разрядов нулями. При выходе за старший разряд сдвигаемые биты теряются.
Если Var1 и Var2 – одна переменная, то можно использовать укороченную форму записи
Var <<= Num;
Пример:
unsigned char n = 0x01; // n = 0b00000001
n = n << 4; // n = 0b00010000
unsigned char m = 0x03; // m = 0b00000011
m <<= 2; // m = 0b00001100
Помимо переменных можно сдвигать числовые константы, например:
Unsigned char n;
n = 1 << 5;
В этом примере единица, представленная своим двоичным значением 0b00000001, сдвигается влево на пять разрядов, и переменная n принимает двоичное значение 0b00100000.
Оператор сдвига вправо >>
Оператор сдвига вправо >> выполняет поразрядный сдвиг числа вправо. Его синтаксис:
Var1 = Var2 >> Num;
Значение переменной Var2 сдвигается вправо на указанное количество разрядов Num с заполнением освободившихся разрядов слева нулями. Следует отметить, что данное утверждение верно, если переменная Var2 беззнакового типа, или если переменная знаковая и ее текущее значение положительное. Если переменная знаковая и ее значение отрицательное, то старшие разряды заполняются единицами. При выходе за нулевой разряд переменной сдвигаемые биты теряются.
Пример:
unsigned char n = 0x80; // n = 0b10000000
n = n >> 4; // n = 0b00001000
unsigned char m = 0xС0; // m = 0b11000000
m >>= 2; // m = 0b00110000
Оператор инверсии ~
Оператор ~ инвертирует каждый разряд операнда, т.е. заменяет 1 на 0 и наоборот. Этот оператор – унарный и применяется только к одному операнду.
Var1 = ~Var2;
Пример:
unsigned char n = 0xAA; // n = 0b10101010
n = ~n; // n = 0b01010101
Оператор логического умножения &
Оператор & производит над операндами логическую операцию поразрядного "И". Это значит, что разряд результата будет равен 1 только в том случае, когда соответствующие разряды обоих операндов содержат 1. В противном случае он будет равен 0.
Var1 = Var2 & Var3;
Пример:
Unsigned char a, b, c;
a = 0x55; // a = 0b01010101
b = 0x01; // b = 0b00000001
c = a & b; // с = 0b00000001
Оператор & часто используется для принудительной очистки заданных разрядов одного из операндов, для чего в качестве второго операнда задается так называемая маска, в которой разряды, требующие очистки, установлены в 0.
Пример:
Unsigned char a, mask;
a = 0x75; // a = 0b01110101
mask = 0x0F; // mask = 0b00001111
a = a & mask; // a = 0b00000101
Оператор логического сложения |
Оператор | производит над операндами логическую операцию поразрядного "ИЛИ". Это значит, что разряд результата будет равен 1, если 1 содержится в соответствующем разряде хотя бы одного операнда.
Var1 = Var2 | Var3;
Пример:
Unsigned char a, b, c;
a = 0x55; // a = 0b01010101
b = 0x81; // b = 0b10000001
c = a | b; // с = 0b11010101
Оператор | применяется для принудительной установки заданных разрядов одного из операндов, при этом во втором операнде задается маска, в которой разряды, подлежащие установке в единицу, равны 1.
Пример:
Unsigned char a, mask;
a = 0x05; // a = 0b00000101
mask = 0xF0; // mask = 0b11110000
a = a | mask; // a = 0b11110101
Оператор сложения по модулю 2 ^
Оператор ^ производит над операндами логическую операцию исключающего "ИЛИ", при которой в каждый разряд результата записывается 1, если соответствующие разряды операндов различаются, и 0, если они совпадают.
Var1 = Var2 ^ Var3;
Пример:
Unsigned char a, b, c;
a = 0x55; // a = 0b01010101
b = 0x03; // b = 0b00000011
c = a^b; // с = 0b01010110
Оператор ^ используется для инверсии заданных битов одного из операндов и для этого во втором операнде задается маска, в которой биты, подлежащие инверсии, установлены в 1.
Пример:
Unsigned char a, mask;
a = 0x55; // a = 0b01010101
mask = 0xF0; // mask = 0b11110000
a = a^mask; // a = 0b10100101