Сдвиг влево ( << )
Сдвигает число на n разрядов влево. Старшие n разрядов при этом исчезают, а младшие n разрядов заполняются нулями.
unsigned char temp = 5; // 0b00000101
temp = temp << 1; // теперь в переменной temp число 10 или 0b00001010
temp = temp << 4; // теперь в переменной temp число 160 или 0b10100000
Выражения, в которых над переменной производится какая-либо операция, а потом результат операции присваивается этой же переменной, можно записывать короче, используя составные операторы.
temp = 42; // 0b00101010
temp <<= 3; // теперь в переменной temp число 80 или 0b01010000
Операция сдвига влево на n разрядов эквивалентна умножению переменной на 2n.
Сдвиг вправо ( >> )
Сдвигает число на n разрядов вправо. Младшие n разрядов при этом теряются. Заполнение старших n разрядов зависит от типа переменной и ее значения. Старшие n разрядов заполняются нулями в двух случаях – если переменная беззнакового типа или если переменная знаковая и ее текущее значение положительное. Когда переменная знаковая и ее значение отрицательное – старшие разряды заполняются единицами.
Пример для беззнаковой переменной
unsigned char temp = 143; // 0b10001111
temp = temp >> 1; // теперь в переменной temp число 71 или 0b01000111
temp >>= 3; // сокращенный вариант записи
// теперь в переменной temp число 8 или 0b00001000
Пример для переменной знакового типа
int temp = 3400; // 0b0000110101001000
temp >>= 2; // теперь в переменной число 850 или 0b0000001101010010
temp = -1200; // 0b1111101101010000
temp >>= 2; // теперь в temp число -600 или 0b1111111011010100
// видите - два старших разряда заполнились единицами
Операция сдвига вправо на n разрядов эквивалентна делению на 2n. При этом есть некоторые нюансы. Если потерянные младшие разряды содержали единицы, то результат подобного “деления” получается грубоватым.
Например 9/4 = 2,5 а 9>>2 (1001 >> 2) равно 2
11/4 = 2,75 а 11>>2 (1011 >> 2) равно 2
28/4 = 7 а 28>>2 (11100 >> 2) равно 7
Во втором случае ошибка больше, потому что оба младших разряда единицы. В третьем случае ошибки нет, потому что потерянные разряды нулевые.
Поразрядная инверсия ( ~ )
Поразрядно инвертирует число. Разряды, в которых были нули – заполняются единицами. Разряды, в которых были единицы – заполняются нулями. Оператор поразрядной инверсии является унарным оператором, то есть используется с одним операндом.
unsigned char temp = 163; //0b10100011
temp = ~temp; //теперь в переменной temp число 92 или 0b01011100
temp = ~temp; //теперь в temp снова число 163 или 0b10100011
Поразрядное ИЛИ ( || )
Оператор | осуществляет операцию логического ИЛИ между соответствующими битами двух операндов. Результатом операции логического ИЛИ между двумя битами будет 0 только в случае, если оба бита равны 0. Во всех остальных случаях результат будет 1. Это проиллюстрировано в таблице истинности.
X1 |
X2 |
X1|X2 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
1 |
Оператор | обычно используют для установки заданных битов переменной в единицу.
temp = 155
temp = temp | 4; //устанавливаем в единицу второй бит переменной temp
155 0b10011011
|
4 0b00000100
159 0b10011111
Использовать десятичные числа для установки битов довольно неудобно. Гораздо удобнее это делать с помощью операции сдвига влево <<.
temp = temp | (1<<5); //устанавливаем в единицу пятый бит переменной temp
Читаем справа налево – сдвинуть единицу на пять разрядов влево, выполнить операцию ИЛИ между полученным числом и значением переменной temp, результат присвоить переменной temp.
Установить несколько битов в единицу можно так
temp = temp | (1 << 8)|(1 << 4)|(1 << 0); //устанавливаем в единицу восьмой, четвертый и нулевой биты переменной temp
С помощью составного оператора присваивания |= можно сделать запись компактней.
temp |= (1 << 7)|(1 << 5)|(1 << 0);
Для примера настроим порт микроконтроллера (PORTA):
DDRA |= (1 << PA6)|(1 << PA4)|(1 << PA2)|(1 << PA0);
Эта запись означает, что линии порта A - 6,4,2,0 работают на выход.
DDRA = (1 << PA4)|(1 << PA3)|(1 << PA2)|(1 << PA1);
Эта же запись означает, что данные биты установлены в "1", однако остальные биты данного регистра обнуляются.
Или еще настроим таймер контроллера.
TCCR0 |= (1 << WGM01) | (1 << COM00) | (1 << CS02) | (1 << CS00);
Такая запись означает, что включен режим СТС, при срабатывании таймера0 меняется состояние вывода ОС0, содержимое счетчика увеличивается каждые 1024 такта.
Поразрядное И ( && )
Оператор & осуществляет операцию логического И между соответствующими битами двух операндов. Результатом операции логического И между двумя битами будет 1 только в том случае, если оба бита равны 1. Во всех других случаях результат будет 0. Это проиллюстрировано в таблице истинности.
X1 |
X2 |
X1&X2 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
1 |
Оператор & обычно применяют, чтобы обнулить один или несколько битов.
temp = 155;
temp = temp & 247; //обнуляем третий бит переменной temp
155 0b10011011
&
247 0b11110111
147 0b10010011
Видите, третий бит стал равен 0, а остальные биты не изменились.
Обнулять биты, используя десятичные цифры, неудобно. Можно записать легче воспользовавшись операторами << и ~
temp = 155;
temp = temp & (~(1 << 3)); //обнуляем третий бит
1 << 3 0b00001000
~(1 << 3) 0b11110111
temp & (~(1 << 3)) 0b10011011 & 0b11110111
результат 0b10010011
Читаем справа налево – сдвинуть единицу на три разряда влево, выполнить инверсию полученного числа, выполнить операцию & между значением переменной temp и проинвертированным числом, результат присвоить переменной temp.
Обнулить несколько битов можно так
temp = temp & (~((1 << 6)|(1 << 3)|(1 << 1))); //обнуляем 6, 3 и 1 биты
Здесь сначала выполняются операции сдвига, потом операции поразрядного ИЛИ, затем инверсия, поразрядное И, присвоение результата переменной temp.
Используя составной оператор присваивания &= ,можно записать выражение более компактно
temp &= (~((1 << 6)|(1 << 3)|(1 << 1)));
Как проверить установлен ли бит в переменной? Нужно обнулить все биты, кроме проверочного, а потом сравнить полученное значение с нулем
if ((temp & (1 << 2)) != 0 ){
// блок будет выполняться, только если установлен
// второй бит переменной temp
}
if ((temp & (1 << 2)) == 0 ){
// блок будет выполняться, только если не установлен
// второй бит переменной temp
}
if ((PINC&(1 << PC0)) == 1){
// блок будет выполняться, если на нулевой линии порта С присутствует единица
}
Поразрядное исключающее ИЛИ ( ^ )
Оператор ^ осуществляет операцию логического исключающего ИЛИ между соответствующими битами двух операндов. Результатом операции логического исключающего ИЛИ будет 0 в случае равенства битов. Во всех остальных случаях результат будет 1. Это проиллюстрировано в табице истинности.
X1 |
X2 |
X1^X2 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
Оператор ^ применяется не так часто как остальные битовые операторы, но и для него находится работенка. Например, с помощью него можно инвертировать один или несколько битов переменной.
temp = 155;
temp = temp ^ 8; // инвертируем третий бит переменой temp
155 0b10011011
^
8 0b00001000
147 0b10010011
Четвертый бит изменил свое значение на противоположное, а остальные биты остались без изменений.
temp = temp ^ 8; // опять инвертируем третий бит переменой temp
147 0b10010011
^
8 0b00001000
155 0b10011011
Видите, четвертый бит снова изменил свое значение на противоположное.
Так записывать выражение намного удобнее
temp = temp ^ (1 << 6); // инвертируем шестой бит переменой temp
А так и удобно и компактно
temp ^= (1 << 2); //инвертируем второй бит
Можно инвертировать несколько битов одновременно
temp ^= ((1 << 7)|(1 << 5)|(1 << 2)); //инвертируем 7, 5 и 2 биты
У поразрядного исключающего ИЛИ есть еще одно интересное свойство. Его можно использовать, для того чтобы поменять значения двух переменных местами. Обычно для этого требуется третья переменная.
temp = var1;
var1 = var2;
var2 = temp;
Но используя оператор ^ переставить значения можно так:
var1 ^= var 2;
var 2 ^= var 1;
var 1 ^= var 2;
Комментарии
Спасибо, исправил