В предыдущей части нашего урока мы узнали, какие бывают операторы такого типа, а также написали функцию, которая будет получать символьный вид двоичного представления числа.
Переходим в функцию main() и объявим там сначала строковый массив, в котором будет храниться полученная строка в результате работы нашей функции, когда мы её будем вызывать
1 2 3 |
int main() { char str1[35] = {}; |
Объявим две переменных и проинициализируем их сразу определёнными числами, которые представим в двоичном виде, а также объявим ещё одну неинициализированную, в которой будет результат нашей операции.
1 2 3 |
char str1[35] = {}; unsigned char a=0b10101010, b=0b10001001; unsigned char res; |
Я не давал такие типы констант в уроке по константам, потому что не каждый компилятор умеет работать с двоичными типами, но наш gcc оказался в этом плане умным.
Произведём операцию & между значениями наших переменных и результат присвоим другой переменной того же типа
1 2 |
unsigned char res; res = a & b; |
С помощью нашей функции отобразим и наши операнды в двоичном виде и результат тоже
1 2 3 4 5 6 7 8 9 |
res = a & b; int_to_binary(a, str1); printf("%srn", str1); printf(" &rn"); int_to_binary(b, str1); printf("%srn", str1); printf("==========rn"); int_to_binary(res, str1); printf("%srn", str1); |
Соберём код и посмотрим результат работы нашего кода
Всё отлично сработало — и операция и функция.
Закомментируем весь написанный нами код в функции main() кроме объявления массива и проделаем аналогичные действия с такими же операндами, но уже с применением операции ИЛИ
1 2 3 4 5 6 7 8 9 10 11 |
unsigned char a=0b10101010, b=0b10001001; unsigned char res; res = a | b; int_to_binary(a, str1); printf("%srn", str1); printf(" |rn"); int_to_binary(b, str1); printf("%srn", str1); printf("==========rn"); int_to_binary(res, str1); printf("%srn", str1); |
Проверим работу кода
Также всё сработало.
Теперь операция Исключающее ИЛИ
1 2 3 4 5 6 7 8 9 10 11 |
unsigned char a=0b10101010, b=0b10001001; unsigned char res; res = a ^ b; int_to_binary(a, str1); printf("%srn", str1); printf(" ^rn"); int_to_binary(b, str1); printf("%srn", str1); printf("==========rn"); int_to_binary(res, str1); printf("%srn", str1); |
Проверим, как это работает
Также всё отлично сработало.
Теперь проверим работу со сдвигами. Сдвигать будем одно и то же число, но в разные стороны и на разное количество пунктов
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
unsigned char a=0b00111000; unsigned char res; res = a>>2; int_to_binary(a, str1); printf("%srn", str1); printf(" a>>2rn"); int_to_binary(res, str1); printf("%srn", str1); res = a<<2; printf(" a<<2rn"); int_to_binary(res, str1); printf("%srn", str1); res = a>>4; printf(" a>>4rn"); int_to_binary(res, str1); printf("%srn", str1); res = a<<4; printf(" a<<4rn"); int_to_binary(res, str1); printf("%srn", str1); |
Посмотрим работу операций
Все операции работают и наглядно показываются в консоли.
Теперь оставшийся унарный оператор отрицания
1 2 3 4 5 6 7 8 |
unsigned char a=0b00111000; unsigned char res; res = ~a; int_to_binary(a, str1); printf("%srn", str1); printf(" ~arn"); int_to_binary(res, str1); printf("%srn", str1); |
Проверяем
Все нули превратились в единицы, а единицы — в нули.
Теперь покажу некоторый смысл наших побитовых операций в тех случаях, когда нам нужно сбросить или выставить определённые биты в каком-то числе. Такой стиль написания кодах при таких операциях мы используем в ситуациях, когда нам нужно сбросить некоторые биты регистров контроллеров или их установить. Кто смотрел мои уроки по контроллерам, тот это видел.
Сначала добавим вот такие вот макросы
1 2 3 4 5 6 7 8 9 10 11 |
#include <stdlib.h> //---------------------------------------------- #define BIT0 0 #define BIT1 1 #define BIT2 2 #define BIT3 3 #define BIT4 4 #define BIT5 5 #define BIT6 6 #define BIT7 7 //---------------------------------------------- |
Это будут номера битов в байте.
Добавим вот такой вот код в функцию main()
1 2 3 4 5 6 7 8 |
unsigned char a=0b11000011; //Установим два бита в числе int_to_binary(a, str1); printf("%srn", str1); a |= ((1<<BIT3) | (1<<BIT4)); printf("bit3 and bit4 SETrn"); int_to_binary(a, str1); printf("%srn", str1); |
Не правда ли, красиво и наглядно вот это?
a |= ((1<<BIT3) | (1<<BIT4));
Здесь происходит присваивание одновременно с операцией ИЛИ. Такой вид присваивания мы будем проходить в одном из следующих уроков. А вообще здесь сначала мы получаем два числа, в которых все нули кроме того бита, который нам надо установить в значении переменной a. Такие числа получаются засчёт того, что мы единицу, являющуюся левым операндом в обоих данных операциях сдвигаем на такое количество пунктов, бит с номером которого мы и хотим установить. Некоторые путают, что будто мы макрос BIT3 или BIT4 сдвигаем на 1 влево. Кто не знаком с операциями сдвига, того может охватить вполне такой оптический обман. Затем результаты наших обоих операций также складываются логически при помощи операции ИЛИ и результатом всего выражения и будет число с установленными битами с индексами наших макросов. Затем происходит операция ИЛИ между значением переменной a, которое она имела до нашей операции с результатом выражения справа и результат данной операции присваивается опять же переменной a. Таким образом, в данной переменной установятся соответствующие биты, а остальные биты не изменят своего состояния.
Проверим, как сработает наш код
Всё сработало. Биты 3 и 4 установились, а остальные не тронулись.
Теперь, наоборот, попытаемся сбросить два бита, не трогая остальные. Делается это уже вот так
1 2 3 4 5 6 7 8 |
unsigned char a=0b11000011; //Сбросим два бита в числе int_to_binary(a, str1); printf("%srn", str1); a &= ~((1<<BIT6) | (1<<BIT1)); printf("bit6 and bit1 RESETrn"); int_to_binary(a, str1); printf("%srn", str1); |
Опять же об данной операции стоит отдельно поговорить
a &= ~((1<<BIT6) | (1<<BIT1));
Происходит всё аналогично. Мы сначала, так сказать, готовим для сброса битов маску. Готовится число с теми установленными битами в байте, которые нам надо, наоборот, сбросить.
Затем мы это число инвертируем с помощью операции отрицания (оператор тильда ~). Затем уже инвертированное число, в котором будут все биты равны единице, за исключением тех, которые надо сбросить. С данным числом и со значением переменной a мы уже производим операцию логического умножения И, в результате которой сбросятся биты с такими номерами, в байтах под номером которых в левом операнде будут нули. А затем результат данной операции опять присвоится переменной a.
Проверим работу нашего кода
Отлично. Биты под номером 6 и 1 сбросились.
Весь сыр-бор с данными сложными операциями из-за того, что в языке C по сравнению с ассемблером нет специальных инструкций по работе с установкой, сбросом и инвертированием отдельных бит.
Итак, на данном занятии мы познакомились с побитовыми операторами, а затем неплохо попрактиковались, за счёт чего многие, я надеюсь, прочувствовали не только, как работать с данными операторами, но и немного поняли их практический смысл. Конечно же, это не всё, мы с битами будем обязательно впоследствии работать много.
Всем спасибо за внимание!
Предыдущая часть Программирование на C Следующий урок
Смотреть ВИДЕОУРОК (нажмите на картинку)
ну и наворотил автор с int2bin. может так проще:
strcpy(in_str,»0b00000000");
if (x && 0x80) in_str[2] = '1';
for (unsigned char i = 0; i<7; i++)
{
x<<=1;
if (x & 0x80) in_str[i+3] = '1';
}
интересно, как в отладчике сравнить 2 программы по времени исполнения
Добрый вечер, Подскажите как правильно передать переменную a=0b11000011 через scanf()?