Побитовые операторы были включены в язык C для удобства низкоуровневой работы с данными и аппаратурой: настройка регистра, маскирование, умножение и деление на степень двойки. Правила их работы сложились ещё во времена 8- и 16-битных процессоров.
Часто ошибаются при сдвигах signed-типов, так как результат зависит от реализации (арифметический или логический сдвиг), а также при выходе за границы размера типа. Ошибки — порча данных, неверные вычисления, неопределенное поведение.
Сдвиг влево (<<): эквивалент умножения значения на 2 в степени k (a << k). Всегда заполняет нули справа.
Сдвиг вправо (>>): для unsigned-значения заполняет слева нулями (логический сдвиг), а для signed — может заполнять как знаковым битом (арифметический сдвиг), так и нулями (поведение зависит от компилятора).
Пример:
unsigned int x = 5; // 0000 0101 unsigned int y = x << 1; // 0000 1010 == 10 int z = -4; // 1111 1100 (если 8 бит) int w = z >> 1; // Может остаться 1111 1110 (-2) или 0111 1110 (зависит от реализации)
Ключевые особенности:
Что произойдет при сдвиге отрицательного числа вправо через >>?
Результат зависит от реализации: чаще всего это арифметический сдвиг с сохранением знака, но стандарт этого не гарантирует!
Чему равен результат сдвига на количество бит больше разрядности типа?
Undefined behavior. Например, 1 << 32 для 32-разрядного типа может дать что угодно или даже нарушить работу программы.
Можно ли использовать побитовые операторы для чисел с плавающей точкой?
Нет, стандартные типы float, double не поддерживают побитовые операции. Только integer-типы.
Программист сдвигал int на 32 для формирования маски — на некоторых платформах это приводило к нулю, на других — нераспознаваемому значению.
Плюсы:
Минусы:
Вместо этого использовались unsigned-значения и маскировка количества битов макросами, с чёткой документацией и проверкой длины типа через sizeof.
Плюсы:
Минусы: