Печать

Занятие №7. Операторы управления битами

Автор: AntonChip Опубликовано . Опубликовано в Программирование на Си

Рейтинг:   / 12
ПлохоОтлично 

Сдвиг влево ( << )

Сдвигает число на 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);

Для примера настроим порт микроконтроллера (PORT A):

DDRA |= (1 << DA0)|(0 << DA1)|(1 << DA2)|(0 << DA3)|(1 << DA4)|(0 << DA5)|(1 << DA6)|(0 << DA7);

Эта запись означает, что линии порта DDA0,2,4,6 работают на выход, остальные на вход. Или еще настроим таймер контроллера.

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;

Комментарии  

0 #1 Mesha 14.12.2011 19:09
В Поразрядном И в таблице истинности единица будет не когда два нуля а когда 2е единиц.
Сообщить модератору
+1 #2 Mesha 14.12.2011 19:20
Получается что оператор & работает по таблице истинности NOR? Получается или здесь неправильно написано или я что-то напутал....
Сообщить модератору
0 #3 Mesha 14.12.2011 19:30
ага все понятно.. все правильно просто таблица истинности логического И неправильная
Сообщить модератору
0 #4 Алекс 12.09.2013 08:12
Админ, в табличке ПОРАЗРЯДНОЕ И вкралась ошибка, единица будет только тогда, когда оба бита равны единице! Исправьте пожалуйста)
Сообщить модератору
0 #5 AntonChip 13.09.2013 15:58
Цитирую Алекс:
Админ, в табличке ПОРАЗРЯДНОЕ И вкралась ошибка, единица будет только тогда, когда оба бита равны единице! Исправьте пожалуйста)

Спасибо, исправил
Сообщить модератору

Рекомендуем посмотреть