>> (bitshift right)
Оператор >> сдвигает биты значения вправо на заданное число позиций — удобен для деления на степени двойки и извлечения отдельных байт.
Полная статья
Описание
Оператор побитового сдвига вправо >> перемещает все биты левого операнда на указанное количество позиций в сторону младших разрядов. Биты, которые «выходят» за правый край, теряются безвозвратно.
Сдвиг вправо на n позиций эквивалентен целочисленному делению на 2ⁿ — это быстрая операция, которую компилятор часто использует сам, но вы можете применять её явно, когда нужна скорость или работа с отдельными битами.
Синтаксис
variable >> number_of_bits;
Параметры
variable: значение, биты которого нужно сдвинуть. Допустимые типы данных: любой целочисленный тип —byte,short,int,long,unsigned shortи другие.number_of_bits: количество позиций для сдвига — положительное число, строго меньшее разрядности типаvariable. Допустимые типы данных:int.
Пример кода
int a = 40; // двоичное: 0000000000101000
int b = a >> 3; // двоичное: 0000000000000101, десятичное: 5
Примечания и предупреждения
Что происходит с крайними битами
Когда выражение x >> y сдвигает значение x вправо на y бит, крайние правые биты выходят за пределы числа и отбрасываются — восстановить их уже нельзя.
То, чем заполняются освободившиеся левые биты, зависит от знаковости типа:
- Если
xимеет беззнаковый тип (например,unsigned int), освободившиеся левые биты заполняются нулями. Это логический сдвиг вправо — предсказуемый и простой. - Если
xимеет знаковый тип (например,int), освободившиеся биты заполняются копией знакового бита (самого левого). Такое поведение называется арифметическим сдвигом или расширением знака — оно гарантирует, что знак результата совпадает со знакомx.
int x = -16; // двоичное: 1111111111110000
int y = 3;
int result = x >> y; // двоичное: 1111111111111110, десятичное: -2
Расширение знака — не всегда желаемое поведение. Если вам нужно, чтобы слева всегда вставлялись нули, приведите переменную к беззнаковому типу перед сдвигом:
int x = -16; // двоичное: 1111111111110000
int y = 3;
int result = (unsigned int) x >> y; // двоичное: 0001111111111110, десятичное: 8190
Сдвиг вправо как деление на степень двойки
Благодаря расширению знака оператор >> корректно делит на степени двойки даже для отрицательных чисел:
int x = -1000;
int y = x >> 3; // целочисленное деление -1000 на 8, результат y = -125
Однако помните, что при работе с отрицательными числами результат округляется в сторону минус бесконечности (то есть «вниз»), а не к нулю, как при обычном делении:
int x = -1001;
int y = x >> 3; // деление сдвигом всегда округляет вниз, результат y = -126
int z = x / 8; // оператор деления округляет к нулю, результат z = -125
Где применяется
- Извлечение отдельных байт из многобайтового значения — например, чтобы получить старший байт
int, достаточно написатьx >> 8. - Быстрое целочисленное деление — сдвиг на 1 делит на 2, на 2 — на 4 и так далее, без операции деления.
- Разбор битовых полей — при чтении данных из регистров периферии или пакетов протоколов вроде I²C и SPI.
- Масштабирование показаний АЦП — перевод 10-битного значения
analogRead()в 8-битный диапазон одним сдвигом>> 2.
Практические замечания
- Сдвигать на количество бит, равное или превышающее разрядность типа, — неопределённое поведение в C++. Для
int(16 или 32 бит в зависимости от платы)number_of_bitsдолжен быть строго меньше этого значения. - Если вы работаете с
byteилиunsigned intи ожидаете нули слева — всё будет именно так. Проблемы с расширением знака возникают только со знаковыми типами. - Чтобы избежать неожиданного расширения знака, объявляйте переменные явно как
unsigned, если в них хранятся битовые маски или сырые данные. - Результат сдвига вправо знакового отрицательного числа зависит от компилятора (стандарт C++ допускает оба варианта), но на Arduino (AVR, ARM) расширение знака работает стабильно.
- При отладке удобно выводить промежуточные значения через
Serial.println(x, BIN)— так сразу видно, какие биты куда сдвинулись.