Программирование на C и C++

Онлайн справочник программиста на C и C++

Битовые операторы

В противоположность большинству языков, С поддерживает все существующие битовые операторы. Поскольку С создавался, чтобы заменить ассемблер, то была необходимость поддержки всех (или по крайней мере большинства) операции, которые может выполнить ассемблер. Битовые операции — это тестирование, установка или сдвиг битов в байте или слове, которые соответствуют стандартным типам языка С char и int. Битовые операторы не могут использоваться с float, double, long double, void и другими сложными типами. Таблица содержит имеющиеся операторы.

Таблица: Битовые операторы
Оператор Действие
& И
| ИЛИ
^ Исключающее ИЛИ
~ Дополнение
>> Сдвиг вправо
<< Сдвиг влево

Битовые операторы И, ИЛИ, НЕ используют ту же таблицу истинности, что и их логические эквиваленты, за тем исключением, что они работают побитно. Исключающее ИЛИ имеет следующую таблицу истинности:

р q p^q
0 0 0
0 1 1
1 0 1
1 1 0

Как следует из таблицы, исключающее ИЛИ выдает истину, если только один из операндов истинен. В противном случае получается ложь.

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

Битовое И чаще всего используется для выключения битов То есть любой бит, установленный в 0, вызывает установку соответствующего бита в Другом операнде также в 0. Например, следующая функция читает символы из порта модема, используя функцию read_modem(), и сбрасывает бит четности в 0.

char get_char_from_modem(void)
{
char ch;
ch = read_modem (); /* получение символа из порта модема * /
return (ch & 127);
}

Четность отображается восьмым битом, который устанавливается в 0 с помощью битового И, поскольку биты с номерами от 1 до 7 установлены в 1, а бит с номером 8 — в 0. Выражение ch & 127 означает, что выполняется битовая операция И между битами переменной ch и битами числа 127. В результате получим ch со сброшенным старшим битом. В следующем примере предполагается, что ch имеет символ 'А' и имеет бит четности:

  бит четности  
  |  
  11000001 ch содержит 'А' с битом четности
  01111111 127 в двоичном представлении выполнение битового И
& ---------------  
  01000001 'А' без бита четности

Битовое ИЛИ может использоваться для установки битов. Любой бит, установленный в любом операнде, вызывает установку соответствующего бита в другом операнде. Например, в результате операции 128 | 3 получаем

  10000000 128 в двоичном представлении
  00000011 3 в двоичном представлении
| -------------- битовое ИЛИ
  10000011 результат

Исключающее ИЛИ или как его называют, XOR устанавливает бит, если соответствующие биты в операндах отличаются. Например, в результате операции 127 ^ 120 получаем

  01111111 127 в двоичном представлении
  01111000 120 к двоичном представлении битовое исключающее
^ -------------- ИЛИ
  00000111 результат

В общем, битовые И, ИЛИ и исключающее ИЛИ применяются к каждому биту переменной. Поэтому битовые операторы обычно не используются в условных операторах, которыми являются операторы отношения и логические операторы. Например: если х содержит 7, то х && 8 выдаст 1, в то время как х & 8 выдаст 0.

ПАМЯТКА: Операторы отношений и логические операторы всегда в качестве результата выдают 0 или 1, в то время как аналогичные им битовые операторы могут создать любое число в соответствии с их работой, другими словами, битовые операторы могут создать значения, отличные от 0 или 1, тогда как логические операторы всегда выдают 0 или 1.

Операторы сдвига >> и << сдвигают биты в переменной вправо и влево на указанное число. Общий вид оператора сдвига вправо:

переменная >> число сдвигов

а общий вид оператора сдвига влево:

переменная << число сдвигов

Помните, что сдвиг — это не то же самое, что и вращение, то есть биты, сдвигающиеся на один конец, не появляются с другого. Сдвинутые биты теряются, а с другого конца появляются нули. В том случае, если вправо сдвигается отрицательное число, слева появляются единицы (поддерживается знаковый бит).

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

  Битовое представление х после выполнения каждого оператора Значение х
char х;    
x = 7;
x = x << 1;
x = x << 3;
x =  x << 2;
х = х >> 1;
x = x >> 2;
00000111
00001110
01110000
11000000
01100000
00011000
7
14
112
192
96
24
Каждый сдвиг влево приводит к умножению на 2. Обратим внимание, что после сдвига х << 2 информация теряется, поскольку биты сдвигаются за конец байта.
Каждый сдвиг вправо приводит к делению на 2. Обратим внимание, что деление не вернуло потерянные биты.

Оператор дополнение, ~, инвертирует состояние каждого бита указанной переменной, то есть 1 устанавливается в 0, а 0 — в 1.

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

Исходный байт
После первого дополнения
После второго дополнения
00101100
11010011
00101100

Надо обратить внимание, что в результате выполнения двух битовых дополнений получаем исходное число. Следовательно, первое дополнение будет создавать кодированную версию байта, а второе будет декодировать.

Можно использовать показанную ниже функцию encode() для кодирования символа:

/* Простейшая шифрующая функция */

char encode(code ch)
{
return(~ch); /* дополнение */
}