Каждое целое число в памяти представлено в виде определенного количества разрядов. И операции сдвига позволяют сдвинуть битовое представление числа на несколько разрядов вправо или влево. Операции сдвига применяются только к целочисленным операндам. Есть две операции:
<<
Сдвигает битовое представление числа, представленного первым операндом, влево на определенное количество разрядов, которое задается вторым операндом.
>>
Сдвигает битовое представление числа вправо на определенное количество разрядов.
Применение операций:
int a = 2 << 2; // 10 на два разрядов влево = 1000 - 8 int b = 16 >> 3; // 10000 на три разряда вправо = 10 - 2
Число 2 в двоичном представлении 10. Если сдвинуть число 10 на два разряда влево, то получится 1000, что в десятичной системе равно число 8.
Число 16 в двоичном представлении 10000. Если сдвинуть число 10 на три разряда вправо (три последних разряда отбрасываются), то получится 10, что в десятичной системе представляет число 2.
Поразрядные операции также проводятся только над разрядами целочисленных операндов:
&: поразрядная конъюнкция (операция И или поразрядное умножение). Возвращает 1, если оба из соответствующих разрядов обоих чисел равны 1
|: поразрядная дизъюнкция (операция ИЛИ или поразрядное сложение). Возвращает 1, если хотя бы один из соответствующих разрядов обоих чисел равен 1
^: поразрядное исключающее ИЛИ. Возвращает 1, если только один из соответствующих разрядов обоих чисел равен 1
~: поразрядное отрицание. Инвертирует все разряды операнда. Если разряд равен 1, то он становится равен 0, а если он равен 0, то он получает значение 1.
Применение операций:
int a = 5 | 2; // 101 | 010 = 111 - 7 int b = 6 & 2; // 110 & 010 = 10 - 2 int c = 5 ^ 2; // 101 ^ 010 = 111 - 7 int f = 12; // 00001100 int d = ~f; // 11110011 или -13 printf("a = %d \n", a); printf("b = %d \n", b); printf("c = %d \n", c); printf("d = %d \n", d);
Например, выражение 5 | 2
равно 7. Число 5 в двоичной записи равно 101, а число 2 - 10 или 010. Сложим соответствующие разряды обоих чисел. При сложении если хотя бы
один разряд равен 1, то сумма обоих разрядов равна 1. Поэтому получаем:
1 | 0 | 1 |
0 | 1 | 0 |
1 | 1 | 1 |
В итоге получаем число 111, что в десятичной записи представляет число 7.
Возьмем другое выражение 6 & 2
. Число 6 в двоичной записи равно 110, а число 2 - 10 или 010. Умножим соответствующие разряды
обоих чисел. Произведение обоих разрядов равно 1, если оба этих разряда равны 1. Иначе произведение равно 0. Поэтому получаем:
1 | 1 | 0 |
0 | 1 | 0 |
0 | 1 | 0 |
Получаем число 010, что в десятичной системе равно 2.
Теперь рассмотрим последний пример - инверсию числа.
Для записи чисел со знаком в Си применяется дополнительный код (two's complement), при котором старший разряд является знаковым. Если его значение равно 0, то число положительное, и его двоичное представление не отличается от представления беззнакового числа. Например, 0000 0001 в десятичной системе 1.
Если старший разряд равен 1, то мы имеем дело с отрицательным числом. Например, 1111 1111 в десятичной системе представляет -1. Соответственно, 1111 0011 представляет -13.
Чтобы получить из положительного числа отрицательное, его нужно инвертировать и прибавить единицу:
int x = 12; int y = ~x; y += 1; printf("y = %d \n", y); // y=-12