Зачем побитовые операции
Перейти к содержимому

Зачем побитовые операции

Битовые операции. Для чего они нужны на примере программировании МК

В своё время я не мог понять смысл таких вещей, как битовые операции. Статьи в интернете не давали мне практического понимания этого вопроса. Со временем, когда я столкнулся с программированием микроконтроллеров (МК), я понял удобство подобных операций, поэтому я решил написать данную статью, чтобы пролить свет на этот вопрос людям, которые только услышали про битовые операции и хотят узнать конкретное практическое применение данных операций. Все примеры будут приведены для tms320f28027.

Операции битового сдвига:

Битовые операции, как можно понять из названия, заключаются в сдвиге битов вправо (>>) или влево (<<).

Давайте предположим, что нам необходимо выставить первый и второй бит в состояние 1, остальные назначить нулями. Для этого мы можем записать

Где 0x00616= 01102, эта запись эквивалентна (1 <<1) + (1 << 2). Таким образом запись выше может быть более наглядно записана:

Кроме этого бывают случаи, когда нам необходимо получить значения только последних битов, для этого может понадобится операция битового сдвига вправо. Например, нам может быть необходимо передать 16 бит данных, при том, что мы можем за раз передать только 8 бит данных. В такой ситуации может пригодится битовый сдвиг вправо, чтобы получить старшие 8 бит. Старшие биты можно не обнулять в случае, если при передаче они не вместятся и обрежутся при передаче 16 битной величине в 8 битный буфер. На стороне приёмника достаточно сдвинуть старшие биты влево и сложить с младшими.

Битовая операция ИЛИ:

Допустим нам необходимо выставить конкретный бит в 1, при этом не меняя весь регистр. Для этого нам может подойти битовая операция ИЛИ. Ниже приведена таблица истинности.

А B A ИЛИ B
0 0 0
0 1 1
1 0 1
1 1 1

Как видно из таблицы выше, в случае отсутствия единицы в нужном нам бите, там
будет выставлена единица согласно операции, а остальные биты не будут задействованы.

Битовые операции И и НЕ

Бывают случаи, когда нам наоборот требуется выставить конкретный бит в состояние 0. Для этого нам необходимо воспользоваться операцией битового И. Для наглядности ниже приведена таблица истинности.

А B A&B
0 0 0
0 1 0
1 0 0
1 1 1

Как видно из таблицы истинности, если произвести операцию битового И с числом, в котором везде единицы, кроме одного бита, то мы сможем выставить 0 в нужном нам бите регистра.

В примере выше 0xFFFFFFF716 = ‭11111111111111111111111111110111‬2
Кроме этого битовая операция И может понадобится для определения наличия бита в конкретном регистре.
Допустим нам надо сразу определить, выставлен 2 или же 3 бит, для этого мы можем произвести операцию

Это выражение истинно, если выставлен любой из 2 и 3 бита или оба бита выставлены одновременно.

Пример выше можно осуществить проще, с помощью комбинирования операции И и НЕ

Заключение

Спасибо всем кто прочитал. Надеюсь такая простая тема найдёт своего читателя.

Битовые операции

Во многих языках программирования допустимы логические операции над битами целых чисел. В отличие от обычных логических операций, результатом выполнения которых является логический тип данных, битовые логические операции просто изменяют целое число согласно определенным правилам. Точнее битовые операции изменяют отдельные биты двоичного представления числа, в результате чего изменяется его десятичное значение.

Например, в языке программирования Паскаль обычные логические операции и логические операции над битами обозначают с помощью одних и тех же ключевых слов: not, and, or, xor . Компилятор определяет, что имелось в виду в зависимости от контекста использования этих слов. Обычные логические операции объединяют два и более простых логических выражения. Например, (a > 0) and (c != b) , (c < a) or(not b) и т.п. В свою очередь побитовые логические операции выполняются исключительно над целыми числами (или переменными, которые их содержат). Например, a and b, a or 8, not 247 .

Как понять побитовые операции

1. Переведем пару произвольных целых чисел до 256 (один байт) в двоичное представление.

2. Теперь расположим биты второго числа под соответствующими битами первого и выполним обычные логические операции к цифрам, стоящим в одинаковых разрядах первого и второго числа. Например, если в последнем (младшем) разряде одного числа стоит 1, а другого числа — 0, то логическая операция and вернет 0, а or вернет 1. Операцию not применим только к первому числу.

3. Переведем результат в десятичную систему счисления.

4. Итак, в результате побитовых логических операций получилось следующее:

Вот еще один пример выполнения логических операций над битами. Проверьте его правильность самостоятельно.

Зачем нужны побитовые логические операции

Глядя на результат побитовых операций, не сразу можно уловить закономерности в их результате. Поэтому непонятно, зачем нужны такие операции. Однако, они находят свое применение. В байтах не всегда хранятся числа. Байт или ячейка памяти может хранить набор флагов (установлен — сброшен), представляющих собой информацию о состоянии чего-либо. С помощью битовых логических операций можно проверить, какие биты в байте установлены в единицу, можно обнулить биты или, наоборот, установить в единицу. Также существует возможность сменить значения битов на противоположные.

Проверка битов

Проверка битов осуществляется с помощью битовой логической операции and .

Представим, что имеется байт памяти с неизвестным нам содержимым. Известно, что логическая операция and возвращает 1, если только оба операнда содержат 1. Если к неизвестному числу применить побитовое логическое умножение (операцию and ) на число 255 (что в двоичном представлении 1111 1111), то в результате мы получим неизвестное число. Обнулятся те единицы двоичного представления числа 255, которые будут умножены на разряды неизвестного числа, содержащие 0. Например, пусть неизвестное число 38 (0010 0110), тогда проверка битов будет выглядеть так:

Другими словами, x and 255 = x .

Обнуление битов

Чтобы обнулить какой-либо бит числа, нужно его логически умножить на 0.

Обратим внимание на следующее:

Т.е. чтобы обнулить четвертый с конца бит числа x , надо его логически умножить на 247 или на (255 — 23).

Установка битов в единицу

Для установки битов в единицу используется побитовая логическая операция or . Если мы логически сложим двоичное представление числа x с 0000 0000, то получим само число х . Но вот если мы в каком-нибудь бите второго слагаемого напишем единицу, то в результате в этом бите будет стоять единица.

Отметим также, что:

Поэтому, например, чтобы установить второй по старшинству бит числа x в единицу, надо его логически сложить с 64 ( x or 64 ).

Смена значений битов

Для смены значений битов на противоположные используется битовая операция xor . Чтобы инвертировать определенный бит числа x , в такой же по разряду бит второго числа записывают единицу. Если же требуется инвертировать все биты числа x , то используют побитовую операцию исключающего ИЛИ ( xor ) с числом 255 (1111 1111).

Операции побитового циклического сдвига

Помимо побитовых логических операций во многих языках программирования предусмотрены битовые операции циклического сдвига влево или вправо. Например, в языке программирования Паскаль эти операции обозначаются shl (сдвиг влево) и shr (сдвиг вправо).

Первым операндом операций сдвига служит целое число, над которым выполняется операция. Во втором операнде указывается, на сколько позиций сдвигаются биты первого числа влево или вправо. Например, 105 shl 3 или 105 shr 4 . Число 105 в двоичном представлении имеет вид 0110 1001.

При сдвиге влево теряются старшие биты исходного числа, на их место становятся младшие. Освободившиеся младшие разряды заполняются нулями.

При сдвиге вправо теряются младшие биты исходного числа, на их место становятся старшие. Освободившиеся старшие разряды заполняются нулями, если исходное число было положительным.

Побитовые операции

342 Но так как переменная типа int занимает 4 байта, т.е. 32 бита, на самом деле число в переменной хранится как: 00000000 00000000 00000001 01010110 — число 342 в переменной типа int в java 11111111 11111111 11111110 10101001 — результат выражения

& — побитовый оператор “И”

  • | — побитовое “ИЛИ”. Принцип работы тот же — сравниваем два числа по битам. Только теперь если хотя бы один из битов равен 1, результат будет равен 1. Посмотрим на тех же числах — 277 и 432:
  • ^ — побитовое исключающее “ИЛИ” (также известно как XOR)

Сдвиг влево

Сдвиг битов влево обозначается знаком << Пример: В этом примере число x=64 называется значением. Именно его биты мы будем сдвигать. Сдвигать биты мы будем влево (это можно определить по направлению знака << ) В двоичной системе число 64 = 1000000 Число y=3 называется количеством. Количество отвечает на вопрос “на сколько бит вправо/влево нужно сдвинуть биты числа x ” В нашем примере мы будем сдвигать их на 3 бита влево. Чтобы процесс сдвига был более понятен, посмотрим на картинке. У нас в примере используются числа типа int. Int ’ы занимают в памяти компьютера 32 бита. Вот так выглядит наше изначальное число 64: Побитовые операции - 2А теперь мы, в прямом смысле слова, берем каждый из наших битов и сдвигаем влево на 3 ячейки: Побитовые операции - 3Вот что у нас получилось. Как видишь, все наши биты сдвинулись, а из-за пределов диапазона добавились еще 3 нуля. 3 — потому что мы делали сдвиг на 3. Если бы мы сдвигали на 10, добавилось бы 10 нулей. Таким образом, выражение x << y означает “сдвинуть биты числа х на y ячеек влево”. Результатом нашего выражения стало число 1000000000, которое в десятичной системе равно 512. Проверим: Вывод в консоль: Все верно! Теоретически, биты можно сдвигать до бесконечности. Но поскольку у нас число int , в распоряжении есть всего 32 ячейки. Из них 7 уже заняты числом 64 (1000000). Поэтому если мы сделаем, например, 27 сдвигов влево, наша единственная единица выйдет за пределы диапазона и “затрётся”. Останутся только нули! Вывод в консоль: Как мы и предполагали, единичка вышла за пределы 32 ячеек-битов и исчезла. У нас получилось 32-битное число, состоящее из одних нулей. Побитовые операции - 4Естественно, в десятичной системе ему соответствует 0. Простое правило для запоминания сдвигов влево: При каждом сдвиге влево выполняется умножение числа на 2. Например, попробуем без картинок с битами посчитать результат выражения 111111111 << 3 Нам нужно трижды умножить число 111111111 на 2. В результате у нас получается 888888888. Давай напишем код и проверим: Вывод в консоль:

Сдвиги вправо

Они обозначаются знаком >> . Делают то же самое, только в другую сторону! 🙂 Не будем изобретать велосипед и попробуем сделать это с тем же числом int 64. Побитовые операции - 5Побитовые операции - 6В результате сдвига на 2 вправо два крайних нуля нашего числа вышли за пределы диапазона и затерлись. У нас получилось число 10000, которому в десятичной системе соответствует число 16 Вывод в консоль: Простое правило для запоминания сдвигов вправо: При каждом сдвиге вправо выполняется деление на два с отбрасыванием любого остатка. Например, 35 >> 2 означает, что нам нужно 2 раза разделить 35 на 2, отбрасывая остатки 35/2 = 17 (отбросили остаток 1) 17:2 = 8 (отбросили остаток 1) Итого, 35 >> 2 должно быть равно 8. Проверяем: Вывод в консоль: Побитовые операции - 7

Приоритет операций в Java

Далее будут выполнены операторы сравнения:

144 <= 119 = false

И, наконец, последним, будет выполнен оператор “И” && .

boolean x = true && false;

boolean x = false;

Оператор сложения ( + ), например, имеет более высокий приоритет, чем оператор сравнения != (“не равно”);

Поэтому в выражении:

boolean x = 7 != 6+1;

сначала будет выполнена операция 6+1, потом проверка 7!=7 (false), а в конце — присваивания результата false переменной x . У присваивания вообще самый маленький приоритет из всех операций — посмотри в таблице.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *