Какие есть битовые операции?cplus-49

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

Основные битовые операции

1. Побитовое И - &

unsigned int a = 0b1100; // 12
unsigned int b = 0b1010; // 10
unsigned int result = a & b; // 0b1000 (8)

Применение:

  • Проверка установленных битов
  • Маскирование (обнуление не нужных битов)

2. Побитовое ИЛИ - |

unsigned int a = 0b1100;
unsigned int b = 0b1010;
unsigned int result = a | b; // 0b1110 (14)

Применение:

  • Установка битов
  • Комбинирование флагов

3. Побитовое исключающее ИЛИ - ^

unsigned int a = 0b1100;
unsigned int b = 0b1010;
unsigned int result = a ^ b; // 0b0110 (6)

Свойства:

  • a ^ a = 0
  • a ^ 0 = a
  • Используется для "переключения" битов

4. Побитовое НЕ - `````

unsigned int a = 0b1100;
unsigned int result = ```a; // 0b...11110011 (инверсия всех битов)

Особенность: Результат зависит от размера типа

5. Сдвиг влево - <<

unsigned int a = 0b0001;
unsigned int result = a << 3; // 0b1000 (8)

Эквивалентно: Умножению на 2^n (если нет переполнения)

6. Сдвиг вправо - >>

unsigned int a = 0b1000;
unsigned int result = a >> 3; // 0b0001 (1)

Эквивалентно: Целочисленному делению на 2^n

Практические примеры

Установка бита

unsigned int setBit(unsigned int num, int pos) {
    return num | (1 << pos);
}

Сброс бита

unsigned int clearBit(unsigned int num, int pos) {
    return num & ```(1 << pos);
}

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

bool isBitSet(unsigned int num, int pos) {
    return num & (1 << pos);
}

Переключение бита

unsigned int toggleBit(unsigned int num, int pos) {
    return num ^ (1 << pos);
}

Продвинутые техники

1. Быстрое умножение/деление на степени двойки

int fastMultiply(int x, int power) {
    return x << power; // x * 2^power
}

int fastDivide(int x, int power) {
    return x >> power; // x / 2^power
}

2. Проверка чётности

bool isEven(int x) {
    return (x & 1) == 0;
}

3. Обмен значений без временной переменной

void swap(int &a, int &b) {
    a ^= b;
    b ^= a;
    a ^= b;
}

4. Поиск младшего установленного бита

int lowestSetBit(int x) {
    return x & -x;
}

Особенности поведения

  1. Знаковые vs беззнаковые сдвиги

    • Для знаковых чисел правый сдвиг (>>) зависит от реализации
    • Беззнаковые всегда сдвигаются с заполнением нулями
  2. Опасности:

    • Сдвиг на величину >= размера типа - неопределённое поведение
    • Переполнение при сдвигах влево
  3. Порядок операций:

    • Битовые операции имеют низкий приоритет
    • Всегда используйте скобки для ясности

Современные альтернативы

  1. Битовые поля:
struct Flags {
    unsigned int isReady : 1;
    unsigned int hasError : 1;
};
  1. std::bitset:
std::bitset<8> bits(0b10101010);
bits.set(3); // Установить бит
bits.test(2); // Проверить бит

Резюмируем: битовые операции - мощный инструмент для эффективной работы с данными на уровне битов. Они незаменимы в системном программировании, оптимизациях и алгоритмах, работающих с битовыми масками. Однако требуют аккуратного использования и понимания их поведения с разными типами данных.