Думаю, раз биты такие важные, что с них мы начали наш урок, нужно познакомится с ними еще ближе. В языке С++ есть несколько операторов, с помощью которых можно проводить различные действия над битами:
~ Битовое Не. Меняет значение бита на противоположное. Вообще, если сравнить 1 с логическим true, а ноль с логическим false (как оно в общем-то и есть) здесь можно использовать аналогию с логическими операторами. Помните пример:
Измените предыдущий пример и убедитесь, что я прав.
^ Исключающее ИЛИ. А вот это нечто новое. Такого мы еще не видели. Оператор ИЛИ возвращает единицу, только если один(только один) из аргументов равен 1.
Помимо логических, для работы с битами также используются операторы сдвига. Это уже знакомые нам << и >>. Они сдвигают все биты числа соответственно влево или вправо, заполняя освободившиеся нолем. Синтаксис использования этих операторов выглядит так:
переменная << число битов переменная >> число битов
здесь число битов, это значение, означающее на сколько нужно произвести сдвиг. Пример:
01011010 << 1 даст 10110100
а
01011010 >> 1 даст 00101101
Отлично, сдвигает. Нам то что с того. Ну например использование комбинация битовых операторов позволяет узнавать или изменять значение каждого бита на свое усмотрение. Для этого придется немного напрячь мозг. Чтобы понять приведенные далее коротенькие примеры необходимо знать то, что я излагал выше.
Проверка бита
Итак, в первую очередь разберемся, как узнать значение конкретного бита переменной v. Для этого используется вот такое очень простое выражение:
Code
(v & (1 <<n))? Бит = 1: Бит = 0;
Эта запись, если вы помните прошлые уроки, использует условный оператор и может быть записана следующим образом:
Code
if(v & (1 << n)) { Бит = 1; } else { Бит = 0; }
Где: v - переменная, n - номер бита.
Работает оно так. Сначала с помощью оператора сдвига создается переменная, в которой интересующий нас бит равен 1. Для этого переменная 1 имеющая двоичное представление 00000001, сдвигается на нужное количество битов влево. Допустим нам нужно узнать значение второго бита. Вспомним, что биты нумеруются от ноля.
(1 << 2) 00000001 << 2 Результат сдвига 00000100
Далее применяем битовый И. Если у переменной второй бит 1 то в результате выражения:
Code
11111111 & 00000100 Получим 00000100 то есть (true)
Если же второй бит равен нолю то:
Code
11111011 & 00000100 Получим 00000000 то есть (false)
Ну а дальше в действие вступает условный оператор, который определяет правдивое выражение или ложное и присваивает соответствующую цифру. Далее я продемонстрирую как с помощью описанного выше способа выполнить преобразование из десятичной системы счисления в двоичную.
Code
#include <iostream> using namespace std; void main() { setlocale(0,""); cout<<"введите число от 0 до 255 "; int i; cin>>i; for(int n=7;n>=0;n--) { cout<<(i & (1 << n) ? 1 : 0); } cin.get(); cin.get(); }
Намного проще, не правда ли. Если кому-то непонятно, замените строку:
Code
cout<<(i & (1 << n) ? 1 : 0);
на:
Code
if(i & (1 << n)) { cout<<1; } else { cout<<0; }
Теперь дошло?
Установка бита в 1
Проверять биты мы научились. Менять их значение еще проще. Здесь даже условный оператор не нужен. Установка бита в 1 выполняется с помощью такого выражения:
Code
v = (v | (1 << n))
Здесь, как и в прошлом случае используется сдвиг для получения переменной, в которой значение конкретного бита 1, остальных 0. Далее используется битовый оператор ИЛИ. Если у переменной второй бит и так 1 то в результате выражения:
11111111 | 00000100 Получим 11111111
Если же второй бит равен нолю то:
000000000 | 00000100 Получим 00000100
Далее результат присваивается исходной переменной.
Для сокращения записи я воспользовался составным присваиванием |=.
Установка бита в 0
А теперь обнулим бит с помощью:
Code
v &= ~(1 << f)
(Здесь тоже составное присваивание &=)
И вновь используется сдвиг, для получения переменной, в которой значение конкретного бита 1, остальных 0. Далее с помощью битового НЕ значение всех битов меняется на противоположное.
~00000100 дает 11111011
Затем, как и в случае проверки, используется битовый И. Если у переменной второй бит 1 то в результате выражения:
01010101 & 11111011 Получим 01010001
Если же второй бит уже равен нолю, то там и менять нечего:
10101010 & 11111011 Получим 10101010
Этот код нужно добавить в приведенный выше пример перед cin.get();.
Вот мы и научились управлять данными на таком тонком уровне как биты. Для полного счастья нам не хватает только добраться до памяти, а конкретно до тех ячеек, в которых вместе со своими битами хранятся переменные. Чем-то подобным мы далее и займемся.