|
Операции с битами. Операции с битами
Операции с битами
Во-первых, это группа команд операций с битами – они предназначены для установки или сброса битов в различных регистрах микроконтроллера, а во-вторых, группа команд передачи управления – они предназначены для организации ветвлений программ. В языке Си естественно нет подобных команд, поэтому у начинающих программистов часто возникает вопрос, а как в Си работать с битами. Эту тему мы сейчас и будем разбирать
В Си существуют 6 операторов для манипулирования битами. Их можно применять к любым целочисленным знаковым или беззнаковым типам переменных.
<< - сдвиг влево >> - сдвиг вправо
- поразрядная инверсия | - поразрядное ИЛИ & - поразрядное И ^ - поразрядное исключающее ИЛИ
_______________ сдвиг влево << _______________ Сдвигает число на n разрядов влево. Старшие n разрядов при этом исчезают, а младшие n разрядов заполняются нулями.
unsigned char tmp = 3; //0b00000011 tmp = tmp << 1; //теперь в переменной tmp число 6 или 0b00000110 tmp = tmp << 3; //теперь в переменной tmp число 48 или 0b00110000
Выражения, в которых над переменной производится какая-либо операция, а потом результат операции присваивается этой же переменной, можно записывать короче, используя составные операторы.
tmp = 7; //0b00000111 tmp <<= 2; //сокращенный вариант записи //теперь в переменной tmp число 28 или 0b00011100
Операция сдвига влево на n разрядов эквивалентна умножению переменной на 2n.
_______________ сдвиг вправо >> _______________ Сдвигает число на n разрядов вправо. Младшие n разрядов при этом теряются. Заполнение старших n разрядов зависит от типа переменной и ее значения. Старшие n разрядов заполняются нулями в двух случаях – если переменная беззнакового типа или если переменная знаковая и ее текущее значение положительное. Когда переменная знаковая и ее значение отрицательное – старшие разряды заполняются единицами.
Пример для беззнаковой переменной
unsigned char tmp = 255; //0b11111111 tmp = tmp >> 1; //теперь в переменной tmp число 127 или 0b01111111 tmp >>= 3; //сокращенный вариант записи //теперь в переменной tmp число 15 или 0b00001111
Пример для переменной знакового типа int tmp = 3400; //0b0000110101001000 tmp >>= 2; //теперь в переменной число 850 или 0b0000001101010010
tmp = -1200; //0b1111101101010000 tmp >>= 2; //теперь в tmp число -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 tmp = 94; //0b01011110 tmp = tmp; //теперь в переменной tmp число 161 или 0b10100001 tmp = tmp; //теперь в tmp снова число 94 или 0b01011110
_______________ поразрядное ИЛИ | ______________
Оператор | осуществляет операцию логического ИЛИ между соответствующими битами двух операндов. Результатом операции логического ИЛИ между двумя битами будет 0 только в случае, если оба бита равны 0. Во всех остальных случаях результат будет 1. Это проиллюстрировано в табице истинности.
Оператор | обычно используют для установки заданных битов переменной в единицу. tmp = 155 tmp = tmp | 4; //устанавливаем в единицу второй бит переменной tmp
155 0b10011011 | 4 0b00000100 159 0b10011111
Использовать десятичные числа для установки битов довольно неудобно. Гораздо удобнее это делать с помощью операции сдвига влево <<.
tmp = tmp | (1<<4); //устанавливаем в единицу четвертый бит переменной tmp
Читаем справа налево – сдвинуть единицу на четыре разряда влево, выполнить операцию ИЛИ между полученным числом и значением переменной tmp, результат присвоить переменной tmp. Установить несколько битов в единицу можно так tmp = tmp | (1<<7)|(1<<5)|(1<<0); //устанавливаем в единицу седьмой, пятый и нулевой биты переменной tmp С помощью составного оператора присваивания |= можно сделать запись компактней.
tmp |= (1<<4); tmp |= (1<<7)|(1<<5)|(1<<0);
_______________ побитовое И & _______________
Оператор & осуществляет операцию логического И между соответствующими битами двух операндов. Результатом операции логического И между двумя битами будет 1 только в том случае, если оба бита равны 1. Во всех других случаях результат будет 0. Это проиллюстрировано в таблице истинности.
Оператор & обычно применяют, чтобы обнулить один или несколько битов. tmp = 155; tmp = tmp & 247; //обнуляем третий бит переменной tmp
155 0b10011011 & 247 0b11110111 147 0b10010011 Видите, третий бит стал равен 0, а остальные биты не изменились. Обнулять биты, используя десятичные цифры, неудобно. Но можно облегчить себе жизнь, воспользовавшись операторами << и
tmp = 155; tmp = tmp & ((1<<3)); //обнуляем третий бит 1<<3 0b00001000
(1<<3) 0b11110111 tmp & ((1<<3)) 0b10011011 & 0b11110111 результат 0b10010011
Читаем справа налево – сдвинуть единицу на три разряда влево, выполнить инверсию полученного числа, выполнить операцию & между значением переменной tmp и проинвертированным числом, результат присвоить переменной tmp. Обнулить несколько битов можно так
tmp = tmp & (((1<<3)|(1<<5)|(1<<6))); //обнуляем третий, пятый и шестой биты
Здесь сначала выполняются операции сдвига, потом операции поразрядного ИЛИ, затем инверсия, поразрядное И, присвоение результата переменной tmp. Используя составной оператор присваивания &= ,можно записать выражение более компактно tmp &= (((1<<3)|(1<<5)|(1<<6))); Как проверить установлен ли бит в переменной? Нужно обнулить все биты, кроме проверочного, а потом сравнить полученное значение с нулем if ((tmp & (1<<2)) != 0 ){ // блок будет выполняться, только если установлен // второй бит переменной tmp } if ((tmp & (1<<2)) == 0 ){ // блок будет выполняться, только если не установлен // второй бит переменной tmp } _______________побитовое исключающее ИЛИ ^ _______________ Оператор ^ осуществляет операцию логического исключающего ИЛИ между соответствующими битами двух операндов. Результатом операции логического исключающего ИЛИ будет 0 в случае равенства битов. Во всех остальных случаях результат будет 1. Это проиллюстрировано в табице истинности.
Оператор ^ применяется не так часто как остальные битовые операторы, но и для него находится работенка. Например, с помощью него можно инвертировать один или несколько битов переменной.
tmp = 155; tmp = tmp ^ 8; // инвертируем четвертый бит переменой tmp 155 0b10011011 ^ 8 0b00001000 147 0b10010011
Четвертый бит изменил свое значение на противоположное, а остальные биты остались без изменений.
tmp = tmp ^ 8; // опять инвертируем четвертый бит переменой tmp
147 0b10010011 ^ 8 0b00001000 155 0b10011011
Видите, четвертый бит снова изменил свое значение на противоположное. Так записывать выражение намного удобнее tmp = tmp ^ (1<<3); // инвертируем третий бит переменой tmp А так и удобно и компактно tmp ^= (1<<4); //инвертируем четверый бит
Можно инвертировать несколько битов одновременно tmp ^= ((1<<4)|(1<<2)|(1<<1)); //инвертируем 4,2 и 1 биты
У поразрядного исключающего ИЛИ есть еще одно интересное свойство. Его можно использовать, для того чтобы поменять значения двух переменных местами. Обычно для этого требуется третья переменная. tmp = var1; var1 = var2; var2 = tmp; Но используя оператор ^ переставить значения можно так: var1 ^= var 2; var 2 ^= var 1; var 1 ^= var 2;3> |
|
|