Побитовые операции в C - Bitwise operations in C

в Язык программирования C, операции могут выполняться на битовый уровень с помощью побитовые операторы.

Побитовые операции противопоставляются байтовый уровень операции, которые характеризуют логические аналоги побитовых операторов - операторы И, ИЛИ и НЕ. Вместо того, чтобы работать с отдельными битами, операторы байтового уровня работают со строками из восьми битов (называемыми байтами) за раз. Причина этого в том, что байт обычно является наименьшей единицей адресуемой памяти (т.е. данными с уникальным адрес памяти ).

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

Все эти операторы также доступны в C ++, и много C-семья языков.

Побитовые операторы

C обеспечивает шесть операторы за битовая манипуляция.[1]

СимволОператор
&побитовое И
|побитовое ИЛИ
^побитовое XOR (исключающее ИЛИ)
<<левый "шифт
>>сдвиг вправо
~побитовое НЕ (дополнение до одного) (унарный)

Побитовое И &

немногобит bа и б (а И б)
000
010
100
111

Побитовый оператор AND представляет собой единственный амперсанд: &. Это просто представление И, которое выполняет свою работу с битами операндов, а не с истинным значением операндов. Побитовое двоичное И выполняет логическое И (как показано в таблице выше) битов в каждой позиции числа в его двоичной форме.

Например, работа с байтом (тип char):

     11001000     & 10111000      --------    = 10001000

В старший бит первого числа - 1, второго - также 1, поэтому наиболее значимый кусочек результата 1; во втором наиболее значимом бите бит второго числа равен нулю, поэтому результат равен 0. [2]

Побитовое ИЛИ |

немногобит bа | б (а ИЛИ б)
000
011
101
111

Как и побитовое И, побитовое ИЛИ работает только на битовом уровне. Его результатом будет 1, если один из битов равен 1, и ноль только тогда, когда оба бита равны 0. Его символ равен | которую можно назвать трубой.

      11001000      | 10111000       --------     = 11111000

[2]

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

немногобит bа ^ б (а XOR б)
000
011
101
110

Побитовое исключающее ИЛИ (исключающее ИЛИ) выполняет логическую функцию исключающего ИЛИ, которая эквивалентна сложению двух битов и отбрасыванию переноса. Результат равен нулю только тогда, когда у нас есть два нуля или две единицы.[3] XOR можно использовать для переключения битов между 1 и 0. Таким образом, я = я ^ 1 при использовании в цикле переключает значения между 1 и 0.[4]

      11001000      ^ 10111000       --------     = 01110000

Побитовое НЕ ~ / одно дополнение (унарный)

немного~ а (дополнение к)
01
10

Дополнение единиц (~) или побитовое дополнение дает нам дополнение данного числа. Таким образом, мы получаем инвертированные биты для каждого бита 1 результат немного 0 и наоборот для каждого бита 0 у нас есть немного 1. Эту операцию не следует путать с логическое отрицание !.

    ~ 11001000         --------     = 00110111

Операторы сдвига

Есть два оператора побитового сдвига. Они есть

  • Сдвиг вправо (>>)
  • Левый "шифт (<<)

Правый сдвиг >>

Символ оператора сдвига вправо: >>. Для его работы требуется два операнды. Он сдвигает каждый бит в своем левом операнде вправо. Число, следующее за оператором, определяет количество мест, на которое будут сдвинуты биты (то есть правый операнд). ch >> 3 все биты будут сдвинуты вправо на три позиции и так далее.

Пример:

Если переменная ch содержит битовый шаблон 11100101, тогда ch >> 1 даст результат 01110010, и ch >> 2 будет производить 00111001.

Здесь пробелы генерируются одновременно слева, когда биты сдвигаются вправо. При выполнении для беззнакового типа выполняемая операция является логический сдвиг, в результате чего пробелы заполняются 0с (нули). При выполнении для подписанного типа результат технически не определен и зависит от компилятора,[5] однако большинство компиляторов выполнят арифметический сдвиг, в результате чего пробел заполняется битом знака левого операнда.

Сдвиг вправо можно использовать для разделения битовой комбинации на 2, как показано:

я = 14; // Битовый шаблон 00001110j = я >> 1; // здесь битовая комбинация сдвинута на 1, поэтому мы получаем 00000111 = 7, что составляет 14/2

Использование оператора сдвига вправо

Типичное использование оператора сдвига вправо в C можно увидеть из следующего кода.

Пример:

#включают <stdio.h>    пустота шоубиты( беззнаковый int Икс ){    int я=0;    за (я = (размер(int) * 8) - 1; я >= 0; я--)    {       путчар(Икс & (1U << я) ? '1' : '0');    }    printf(" п");}int главный( пустота ){    int j = 5225;    printf("% d в двоичном формате  т  т ", j);    / * предполагаем, что у нас есть функция, которая печатает двоичную строку при задании        десятичное целое число     */    шоубиты(j);    / * цикл для операции сдвига вправо * /    за (int м = 0; м <= 5; м++)    {        int п = j >> м;        printf("% d сдвиг вправо% d дает", j, м);        шоубиты(п);    }    возвращаться 0;}

Результатом вышеуказанной программы будет

5225 в двоичном формате 000000000000000000010100011010015225 сдвиг вправо 0 дает 000000000000000000010100011010015225 сдвиг вправо 1 дает 000000000000000000001010001101005225 сдвиг вправо 2 дает 000000000000000000000101000110105225 сдвиг вправо 3 дает сдвиг вправо 3 дает 00000000000000000000000000000000000000000000000000000000

Левый "шифт <<

Символ оператора сдвига влево: <<. Он сдвигает каждый бит в своем левом операнде влево на количество позиций, указанных в правом операнде. Он работает противоположно оператору сдвига вправо. Таким образом, делая ch << 1 в приведенном выше примере у нас есть 11001010Создаваемые пустые места заполняются нулями, как указано выше.

Сдвиг влево можно использовать для умножения целого числа на степень 2, как в

int я = 4; / * эквивалент битовой комбинации 100 * /int j = я << 2; / * делает его двоичным 10000, что умножает исходное число на 4, т.е. 16 * /

Пример: простая программа сложения

Следующая программа добавляет два операнда с помощью AND, XOR и сдвига влево (<<).

#включают <stdio.h>int главный( пустота ){    беззнаковый int Икс = 3, у = 1, сумма, нести;    сумма = Икс ^ у; // x XOR y    нести = Икс & у; // x И y    пока (нести != 0)    {        нести = нести << 1; // сдвиг влево перенос        Икс = сумма; // инициализируем x как сумму        у = нести; // инициализируем y как перенос        сумма = Икс ^ у; // сумма рассчитывается        нести = Икс & у; / * вычисляется перенос, условие цикла                           оценивается, и процесс повторяется до тех пор, пока                           перенос равен 0.                        */    }    printf("% u п", сумма); // программа напечатает 4    возвращаться 0;}

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

C предоставляет составной оператор присваивания для каждого двоичный арифметические и побитовые операции (т.е. каждая операция, которая принимает два операнда). Каждый из составных операторов поразрядного присваивания выполняет соответствующую двоичную операцию и сохраняет результат в левом операнде.[6]

Операторы поразрядного присваивания следующие:

СимволОператор
&=побитовое И присваивание
|=присваивание побитового инклюзивного ИЛИ
^=присваивание побитового исключающего ИЛИ
<<=назначение левой смены
>>=назначение сдвига вправо

Логические эквиваленты

Четыре побитовых оператора имеют эквивалентные логические операторы. Они эквивалентны тем, что имеют одинаковые таблицы истинности. Однако логические операторы обрабатывают каждый операнд как имеющий только одно значение, истинное или ложное, вместо того, чтобы рассматривать каждый бит операнда как независимое значение. Логические операторы считают ноль ложью, а любое ненулевое значение - истиной. Другое отличие состоит в том, что логические операторы выполняют оценка короткого замыкания.

Таблица ниже соответствует эквивалентным операторам и показывает a и b как операнды операторов.

ПобитовоеЛогический
а и ба && б
а | ба || б
а ^ ба! = Ь
~ а! а

!= имеет ту же таблицу истинности, что и ^ но в отличие от настоящих логических операторов, сам по себе != не является, строго говоря, логическим оператором. Это потому, что логический оператор должен обрабатывать любое ненулевое значение одинаково. Для использования в качестве логического оператора != требует, чтобы сначала были нормализованы операнды. Логика, не примененная к обоим операндам, не изменит результирующую таблицу истинности, но обеспечит преобразование всех ненулевых значений в одно и то же значение перед сравнением. Это работает, потому что ! на нуле всегда приводит к единице и ! на любом ненулевом значении всегда приводит к нулю.

Пример:

/ * Эквивалентные побитовые и логические тесты операторов * /#включают <stdio.h>пустота testOperator(char* имя, беззнаковый char был, беззнаковый char ожидал);int главный( пустота ){   // - Побитовые операторы - //   // Таблицы истинности упакованы в биты   const беззнаковый char операнд1    = 0x0A; //0000 1010   const беззнаковый char операнд2    = 0x0C; //0000 1100   const беззнаковый char ожидается = 0x08; //0000 1000   const беззнаковый char ожидается или  = 0x0E; //0000 1110   const беззнаковый char ожидаетсяXor = 0x06; //0000 0110	   const беззнаковый char операнд3    = 0x01; //0000 0001   const беззнаковый char ожидаетсяНет = 0xFE; //1111 1110   testOperator(«Побитовое И», операнд1 & операнд2, ожидается);   testOperator(«Побитовое ИЛИ», операнд1 | операнд2, ожидается или);   testOperator(«Побитовое исключающее ИЛИ», операнд1 ^ операнд2, ожидаетсяXor);   testOperator(«Побитовое НЕ», ~операнд3, ожидаетсяНет);	   printf(" п");   // - Логические операторы - //   const беззнаковый char F = 0x00; //Нуль   const беззнаковый char Т = 0x01; // Любое ненулевое значение   // Таблицы истинности упакованы в массивы   const беззнаковый char operandArray1[4]    = {Т, F, Т, F};   const беззнаковый char operandArray2[4]    = {Т, Т, F, F};   const беззнаковый char ожидаемыйArrayAnd[4] = {Т, F, F, F};   const беззнаковый char ожидаемыйArrayOr[4]  = {Т, Т, Т, F};   const беззнаковый char ожидаемыйArrayXor[4] = {F, Т, Т, F};	   const беззнаковый char operandArray3[2]    = {F, Т};   const беззнаковый char ожидаемыйArrayNot[2] = {Т, F};   int я;   за (я = 0; я < 4; я++)   {      testOperator(«Логическое И», operandArray1[я] && operandArray2[я], ожидаемыйArrayAnd[я]);   }   printf(" п");   за (я = 0; я < 4; я++)   {      testOperator(«Логическое ИЛИ», operandArray1[я] || operandArray2[я], ожидаемыйArrayOr[я]);   }   printf(" п");   за (я = 0; я < 4; я++)   {      // Необходимо! на операндах в случае, если отличные от нуля значения      testOperator(«Логический XOR», !operandArray1[я] != !operandArray2[я], ожидаемыйArrayXor[я]);   }   printf(" п");   за (я = 0; я < 2; я++)   {      testOperator(«Логическое НЕ», !operandArray3[я], ожидаемыйArrayNot[я]);   }   printf(" п");   возвращаться 0;}пустота testOperator( char* имя, беззнаковый char был, беззнаковый char ожидал ){   char* результат = (был == ожидал) ? "прошедший" : "не удалось";   printf("% s% s тест:% X ожидалось:% X  п", имя, результат, был, ожидал);    }

Результатом вышеуказанной программы будет

 Поразрядное И прошло, было: 8 ожидалось: 8 Поразрядное ИЛИ прошло, было: E ожидалось: E Побитовое XOR прошло, было: 6 ожидалось: 6 Побитовое НЕ прошло, было: ожидалось: FE Логическое И прошло, было: 1 ожидалось: 1 Логическое И прошло, было: 0 ожидалось: 0 Логическое И прошло, было: 0 ожидалось: 0 Логическое И прошло, было: 0 ожидалось: 0 Логическое И прошло, было: 1 ожидалось: 1 Логическое ИЛИ прошло, было: 1 ожидалось: 1 Логическое ИЛИ прошло, было: 1 ожидалось: 1 Логическое ИЛИ прошло, было: 0 ожидалось: 0 Логическое исключающее ИЛИ прошло, было: 0 ожидалось: 0 Логическое ИЛИ прошло, было: 1 ожидалось: 1 Логическое ИЛИ прошло, было: 1 ожидалось: 1 Логический XOR прошел, было: 0 ожидалось: 0 Логическое НЕ прошло, было: 1 ожидалось: 1 Логическое НЕ прошло, было: 0 ожидалось: 0

Смотрите также

Рекомендации

  1. ^ Керниган; Деннис М. Ричи (Март 1988 г.). Язык программирования C (2-е изд.). Энглвуд Клиффс, Нью-Джерси: Prentice Hall. ISBN  0-13-110362-8. Архивировано из оригинал на 2019-07-06. Получено 2019-09-07. Многие считают его авторитетной ссылкой на C.
  2. ^ а б «Учебники - Побитовые операторы и битовые манипуляции в C и C ++». cprogramming.com.
  3. ^ "Учебное пособие по эксклюзивным операционным воротам". Базовые руководства по электронике.
  4. ^ «Примечания C ++: побитовые операторы». fredosaurus.com.
  5. ^ «3.8 - Побитовые операторы». Изучите C ++.
  6. ^ «Составные операторы присваивания C / C ++». XL C / C ++ V8.0 для AIX. IBM. Получено 11 ноября 2013.

внешняя ссылка