На этом шаге мы рассмотрим особенности использования побитовых операторов.
После того, как мы кратко познакомились на предыдущем шаге со способами бинарного колирования чисел, перейдем к обсуждению побитовых операторов. Они перечислены в таблице 1.
Оператор | Описание |
---|---|
& | Оператор "побитовое и". Результатом выражения А&В является число, которое получается сравнением соответствующих битов в представлении чисел А и В. На выходе получается единичный бит, если оба сравниваемых бита единичные. Если хотя бы один из сравниваемых битов нулевой, в результате получаем нулевой бит |
| | Оператор "побитовое или". Значение выражения вида А | В есть число, получаемое сравнением соответствующих битов в представлении чисел А и В. На выходе получается единичный бит, если хотя бы один из сравниваемых битов единичный. Если оба сравниваемых бита нулевые, в результате получаем нулевой бит |
^ | Оператор "побитовое исключающее или". Значением выражения А^В является число результат сравнения соответствующих битов в представлении чисел А и В. На выходе получается единичный бит, если сравниваемые биты различны (один единичный, а другой нулевой). Если биты одинаковые (оба единичные или оба нулевые), то в результате получаем нулевой бит |
~ | Оператор "побитовая инверсия". Значение выражения вида ~А есть число, битовое представление которого получается заменой в битовом представлении числа А нулей на единицы и единиц на нули. Значение операнда А при этом не меняется |
<< | Оператор "сдвиг влево". Результатом выражения А<<B является число, которое получается путем сдвига бинарного представления числа А на B позиций влево. Младшие биты при этом заполняются нулями, а старшие теряются. Значение операнда А остается неизменным |
>> | Оператор "сдвиг вправо". Значение выражения А>>B равно числу, которое получается путем сдвига бинарного представления числа А на B позиций вправо. Младшие биты при этом теряются, а старшие заполняются значением старшего (знакового) бита. Значение операнда А остается неизменным |
Вообще побитовые операторы напоминают логические, с поправкой на то, что операции выполняются с битами, истинному значению соответствует 1, а ложному значению соответствует 0. Например, при вычислении выражения А&В на основе оператора "побитового и" в результате получается целое число. Его бинарный код вычисляется так: сравниваются биты, находящиеся на одинаковых позициях в представлении чисел А и В. Правила сравнения даются в таблице 2.
a | 1 | 0 |
---|---|---|
b | ||
1 | 1 | 0 |
0 | 0 | 0 |
Если оба бита единичные, то в соответствующем месте в коде для числа-результата записывается единица. Если хотя бы один из двух сравниваемых битов нулевой, то в число-результат записывается нулевой бит.
Как пример простой операции с использованием оператора "побитового и" & рассмотрим следующий блок программного кода:
byte А=13, В=25, С; С=(byte)(А&В);
В данном случае имеем дело с тремя переменными А, В и С типа byte. Это значит, что значение каждой из переменных запоминается с помощью 8 битов.
Десятичное число 13 в двоичном 8-битовом коде записывается как 00001101, а числу 25 соответствует бинарный код 00011001.
Операция "побитовое и" выполняется так:
00001101 & 00011001 ---------- 00001001
Следовательно, в результате получаем бинарный код 00001001. Несложно проверить, что это код числа 23 + 20 = 9. Таким образом, при выполнении указанного выше программного кода значения переменных будут следующими: значение переменной А равно 13, значение переменной В равно 25, а значение переменной С равно 9.
Если используется оператор "побитовое или" |, то при сравнении двух битов в результате получаем единичный бит, если хотя бы один из сравниваемых битов единичный. Правила выполнения этой операции проиллюстрированы в таблице 3.
a | 1 | 0 |
---|---|---|
b | ||
1 | 1 | 1 |
0 | 1 | 0 |
Рассмотрим, как операция "побитовое или" выполняется с уже знакомыми для нас переменными:
byte А=13, В=25, С; С=(byte)(А|В);
В соответствии с правилами выполнения операции получаем следующий результат:
00001101 | 00011001 ---------- 00011101
Бинарный код 00011101 соответствует десятичному числу 29, поскольку имеет место соотношение 24 + 23 + 22 + 20 = 29. Таким образом, переменная С в данном случае будет иметь значение 29.
Если выполняется операция "побитовое исключающее или", то двоичные коды для двух исходных чисел сравниваются с использованием такой схемы: если на одинаковых позициях в битовых представлениях чисел значения разные (то есть один бит единичный, а другой нулевой), то на "выходе" получаем единицу. Если у сравниваемых чисел на одинаковых позициях находятся одинаковые биты (то есть биты с одинаковыми значениями), в числе-результате на соответствующем месте будет нулевой бит (бит с нулевым значением). Правила выполнения операции "побитовое исключающее или" проиллюстрированы в таблице 4 для двух отдельных битов.
a | 1 | 0 |
---|---|---|
b | ||
1 | 0 | 1 |
0 | 1 | 0 |
Результат применения операции "побитовое исключающее или" к числовым значениям 13 и 25 приводит к следующему результату:
00001101 ^ 00011001 ---------- 00010100
Мы получаем бинарный код 00010100, который соответствует десятичному числу 20 (поскольку 24 + 22 = 20). Допустим, мы имеем дело, например. с таким блоком программного кода:
byte А=13, В=25, С; С=(byte)(А^В);
В результате его выполнения переменная С получит значение 20.
Оператор "побитовая инверсия" является унарным. Побитовая инверсия выполняется просто: в битовом представлении числа нули меняются на единицы, а единицы меняются на нули. Это правило, по которому вычисляется результат. Операнд при этом не меняется. В таблице 5 показано, как операция побитовой инверсии выполняется для одного отдельного бита.
a | 1 | 0 |
---|---|---|
~a | 0 | 1 |
Например, имеется такой блок программного кода:
byte А, В; A=13; B=(byte)~А;
Вопрос состоит в том, какие значения будут у целочисленных переменных А и В после выполнения указанных команд? Ответ, в принципе, простой: значение переменной А равно 13, а значение переменной В равно 242. Самая простая ситуация с переменной А. Ей присваивается значение 13. Это число в десятичной системе. В двоичной системе код значения переменной А имеет вид 00001101. Но в данном случае это не столь важно, поскольку при выполнении команды В=(byte)~А значение переменной А не меняется: побитовая инверсия применяется для вычисления результата выражения ~А, но сам операнд А не меняется. Поэтому переменная А остается со своим, ранее присвоенным значением (число 13).
Если применить операцию побитового инвертирования к коду 00001101 числа 13, то в бинарном 8-битовом представлении иолучим код 11110010. Этот код соответствует числу 27 + 26 + 25 + 24 + 21 = 128 + 64 + 32 + 16 + 2 = 242. Таким образом, переменная В получает значение 242. Но еще раз подчеркнем, что в данном случае важно, что тип byte предназначен для реализации неотрицательных чисел. Если мы вместо типа byte воспользуемся типом sbyte, результат побитовой инверсии будет иным. Точнее, он будет по-другому интерпретироваться. Допустим, имеется такой код:
sbyte А, В; A=13; B=(sbyte)~А;
Вопрос состоит в том, каково значение переменной B? Строго говоря, как и в предыдущем случае, значение переменной В будет представлено кодом 11110010. Но теперь, поскольку это sbyte-значение, код интерпретируется как число со знаком. Так как старший бит единичный, то число отрицательное. Чтобы понять, что это за число, мы должны:
Поскольку нам предстоит инвертировать то, что было получено инвертированием, мы сначала получим бинарный код для числа 13, затем прибавим к этому числу 1 (получим 14) и, дописав знак "минус", получаем значение -14 для переменной В.
Еще две побитовые операции, которые нам осталось обсудить - сдвиг влево и сдвиг вправо. Например, рассмотрим следующий программный код:
byte А=13, В, С; B=(byte)(А<<2); C=(byte)(А>>2);
Чтобы получить значение переменной B, мы должны взять код 00001101 для числа 13 (значение переменной А) и выполнить сдвиг этого кода влево на две позиции. В результате получаем код 00110100. Это код числа 52 - значение переменной В. Значение переменной A остается неизменным.
Для вычисления значения переменной С бинарный код значения переменной А сдвигается вправо на две позиции. В результате из кода 00001101 получаем код 00000011, что соответствует числу 3. Это и есть значение переменной С.
На следующем шаге мы рассмотрим оператор присваивания.