Битовые сдвиги в C++ как и в других языках программирования относят к логическим операциям, эти операции обычно выполняются над беззнаковыми целыми числами, позволяя быстро поделить на 2 (сдвиг >>) или умножить на 2 (сдвиг <<).
Вообще, здесь нужно вспомнить, что любое целое число представляется в двоичной системе счисления
b(a0 + a1*2 + a2*22 + a3*23 +...+ an*2n),
здесь a0, a1, a2,..., an - числа 0 и 1; b - знаковый бит: -1 или 1.
В ячейки памяти ЭВМ 0 и 1 из представления числа записываются в следующем порядке:
b an ... a3 a2 a1 a0
Существуют также беззнаковые типы данных (unsigned)
В этом случае знаковый бит не пишется и порядок записи такой:
an ... a3 a2 a1 a0
Например,
142 = 0*1 + 1*2 + 1*22 + 1*23 + 0*24 + 0*25 + 0*26 + 1*27 = 10001110
Количество битов выделяемых на целое число определяется его типом (short - короткие, long - длинные и т.д.) и конкретной реализацией языка.
Функционал сдвиговых операций заключается в том, что каждый бит в переменной заменяется соседним.
Направление зависит от вида сдвига, которых всего два: сдвиг вправо - “>>” и сдвиг влево - “<<”. Пример такого сдвига:
1 2 |
unsigned short a = 1024; unsigned short b = a >> 1; |
Значение b будет равно 512. То есть сдвиг вправо эквивалентен делению на 2, а сдвиг влево умножению на 2. Сдвиговые операции быстрее умножения и деления на 2 обычным способом.
При сдвигах вопрос вызывают крайние биты, для которых нет сдвигаемого значения или места в переменной. Например, если мы сдвинем влево переменную a на 6, мы получим что число 1024, а точнее 0000010000000000, выйдет из пределов unsigned short, а так же появятся биты, которые займут места первых 6 сдвинутых битов. На этот счет в C++ есть правило: если сдвигаемый бит нечем заменить, замена производится на 0. Так, же если сдвигаемый бит есть, а места под него нет, то есть выходит за границы типа, то возникает переполнение. Результат такой функции сильно зависит от используемой платформы, и применять такой подход не рекомендуется.
Аналогично и с числами со знаками. Использует ли их как еще 1 бит или просто откинет зависит от платформы.
В некоторых случаях можно избежать переполнения, используя автоопределение типа полученного числа. Работает только у целочисленных типов.
1 2 |
char a = 's'; auto b = a << 1; |
Тип b станет int, по правилам восходящих приведений типов в C++.