1. Обзор побитовых операций

В современных компьютерах все данные хранятся в двоичной форме, то есть в двух состояниях: 0 и 1. Операции, выполняемые компьютерами над двоичными данными (такие как сложение, вычитание, умножение и деление), называются побитовыми операциями, то есть операциями, которые воздействуют на каждый бит двоичного числа.

Чтобы лучше понять побитовые операции, вот простой пример: предположим, у нас есть следующий код для сложения двух целых чисел:

int a = 35;
int b = 47;
int c = a + b;

Компьютер преобразует эти два целых числа в двоичную форму, а затем выполняет сложение:

35:  0010 0011
47:  0010 1111
----------------
82:  0101 0010

Следовательно, по сравнению с прямым использованием+、-、*、/операторов, разумное использование побитовых операций может значительно повысить эффективность выполнения кода на машине.

2. Побитовые операции: краткий обзор

Символ Описание Правило операции
& и Результат равен 1 только тогда, когда оба бита равны 1.
| или Результат равен 0 только тогда, когда оба бита равны 0.
^ Исключающее ИЛИ Результат равен 0, если два бита одинаковы, и 1, если они различаются.
~ НЕ 0 становится 1, а 1 становится 0.
<< Сдвиг влево Все биты сдвигаются влево на определённое число позиций; старшие биты отбрасываются, а младшие заполняются 0.
>> Сдвиг вправо Все биты сдвигаются вправо на определённое число позиций; старшие биты заполняются 0 или знаковым битом.

3. Оператор побитового И (&)

Определение: выполняет операцию "И" над двоичными битами двух участвующих операндов данных.

Правило операции:

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

Кратко: только когда оба бита равны 1, результат равен 1; в противном случае результат равен 0.

Например:3 & 5i.e.0000 0011 & 0000 0101 = 0000 0001, следовательно3 & 5значение равно 1.

Примечание: отрицательные числа участвуют в побитовых операциях И в форме дополнительного кода.

Приложения:

  1. Обнуление: если вы хотите обнулить единицу, просто выполните над ней операцию И со значением, все биты которого равны нулю; результат будет равен нулю.
  2. Извлечение указанных битов числа: например, возьмитеX = 1010 1110младшие 4 бита числа, просто найдите другое числоY = 0000 1111, затемX & Y = 0000 1110можно получитьXуказанные биты.
  3. Определение нечётного или чётного: проверяя, равен ли младший значащий бит 0 или 1 для определения чётности, можно использоватьif ((a & 1) == 0)вместоif (a % 2 == 0)чтобы определить,aявляется ли оно чётным.

4. Оператор побитового OR (|)

Определение: выполняет операцию "OR" над двоичными битами двух задействованных операндов.

Правило операции:

0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

Резюме: Если хотя бы один из них равен 1, результат равен 1.

Например:3 | 5i.e.0000 0011 | 0000 0101 = 0000 0111, следовательно3 | 5значение равно 7.

Примечание: Отрицательные числа участвуют в побитовых операциях OR в дополнительном коде.

Приложения:

  1. Установка определённых битов в 1: Например, чтобы установитьX = 1010 1110младшие 4 бита числа в 1, просто найдите другое числоY = 0000 1111, затемX | Y = 1010 1111вы можете получить это.

5. Оператор побитового XOR (^)

Определение: выполняет операцию "XOR" над двоичными битами двух задействованных операндов данных.

Правило операции:

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

Кратко: Если соответствующие биты совпадают, результат равен 0; если они различаются, результат равен 1.

Свойства:

  1. Коммутативный закон
  2. Ассоциативный закон:(a ^ b) ^ c == a ^ (b ^ c)
  3. Для любого числаx, справедливо, чтоx ^ x = 0,x ^ 0 = x
  4. Самообратимость:a ^ b ^ b = a ^ 0 = a

Приложения:

  1. Инвертировать указанные биты: Например, чтобы инвертироватьX = 1010 1110младшие 4 бита числа, просто найдите другое числоY = 0000 1111, затемX ^ Y = 1010 0001вы можете получить это.
  2. XOR с 0 сохраняет значение неизменным: например1010 1110 ^ 0000 0000 = 1010 1110
  3. Обмен двух чисел:
void Swap(int &a, int &b) {
if (a != b) {
    a ^= b;
    b ^= a;
    a ^= b;
}
}

6. Побитовый оператор НЕ (~)

Определение: выполняет операцию "НЕ" над двоичными битами единственного задействованного операнда.

Правило операции:

~1 = 1111 1110
~0 = 1111 1111

То есть:

~1 = -2
~0 = -1

Кратко: меняет 0 на 1, а 1 на 0.

Приложения:

  1. Установить младший значащий бит числа в ноль: Например, чтобы установитьaУстановка младшего значащего бита числа в 0 может быть выражена так:a & ~1。~1значение ... равно1111 1111 1111 1110, затем выполнить операцию "AND", и младший значащий бит обязательно будет равен 0.

7. Оператор сдвига влево (<<)

Определение: Сдвинуть все двоичные биты операнда влево на определённое количество позиций; старшие биты отбрасываются, а младшие заполняются 0.

Например, пустьa = 1010 1110,a = a << 2будетaдвоичные биты ... сдвигаются влево на 2 позиции, справа заполняются нулями, в результате получаетсяa = 1011 1000。

Если старшие биты, отбрасываемые при сдвиге влево, не содержат 1, то каждый сдвиг влево на одну позицию эквивалентен умножению числа на 2.

8. Оператор сдвига вправо (>>)

Определение: Сдвинуть все двоичные биты числа вправо на определённое количество позиций; старшие биты заполняются 0 или знаковым битом, а правая сторона отбрасывается.

Например,a = a >> 2будетaдвоичные биты ... сдвигаются вправо на 2 позиции, левая сторона заполняется 0 или знаковым битом, в зависимости от того, является ли число положительным или отрицательным.

Каждый раз, когда операнд сдвигается вправо на одну позицию, это эквивалентно делению числа на 2.

9. Составные операторы присваивания

Поразрядные операторы объединяются с операторами присваивания, образуя новые составные операторы присваивания, а именно:

  • &= Пример:a &= bэквивалентноa = a & b
  • |= Пример:a |= bэквивалентноa = a | b
  • >>= Пример:a >>= bэквивалентноa = a >> b
  • <<= Пример:a <<= bэквивалентноa = a << b
  • ^= Пример:a ^= bэквивалентноa = a ^ b

Правила выполнения операций аналогичны правилам составных операторов присваивания, упомянутых выше.

Поразрядные операции над данными разной длины:

Если два элемента данных разной длины участвуют в поразрядной операции, система выравнивает их по правым концам, а затем выполняет поразрядную операцию.

Возьмём в качестве примера «операцию И»:

В языке C,longтип занимает 4 байта,intтип занимает 2 байта. Еслиlongданные типа иintданные типа подвергаются «операции И»; после выравнивания по правому краю недостающие биты слева заполняются в соответствии со следующими тремя случаями:

  1. Если целочисленные данные положительны, левые биты заполняются 16 нулями.
  2. Если целочисленные данные отрицательные, левые биты заполняются 16 единицами.
  3. Если целочисленные данные беззнаковые, левые биты также заполняются 16 нулями.

Например:

long a = 123;
int b = 1;
long result = a & b;
long a = 123;
unsigned int b = 1;
long result = a & b;