Шрифт:
Ниже приведен результат выполнения этой программы. Исходное сообщение: Hi! Зашифрованное сообщение: 1y Расшифрованное сообщение: Hi!
Как видите, в результате выполнения двух последовательностей поразрядных опе раций исключающее ИЛИ получается расшифрованное сообщение. (Еще раз напом ним, что такое шифрование не имеет никакой практической ценности, поскольку оно, в сущности, ненадежно.)
Поразрядный унарный оператор НЕ (или оператор дополнения до 1) изменяет на обратное состояние всех двоичных разрядов операнда. Так, если некоторое целое зна чение А имеет комбинацию двоичных разрядов 1001 0110, то в результате поразрядной операции ~А получается значение с комбинацией двоичных разрядов 0110 1001.
В следующем примере программы демонстрируется применение поразрядного оператора НЕ с выводом некоторого числа и его дополнения до 1 в двоичном коде. // Продемонстрировать применение поразрядного унарного оператора НЕ. using System; class NotDemo { static void Main { sbyte b = -34; for(int t=128; t > 0; t = t/2) { if((b & t) != 0) Console.Write("1 "); if((b & t) == 0) Console.Write("0 "); } Console.WriteLine; // обратить все биты b = (sbyte) ~b; for(int t=128; t > 0; t = t/2) { if((b & t) != 0) Console.Write("1 "); if((b & t) == 0) Console.Write("0 "); } } }
Результат выполнения этой программы приведен ниже. 1 1 0 1 1 1 1 0 0 0 1 0 0 0 0 1 Операторы сдвига
В C# имеется возможность сдвигать двоичные разряды, составляющие целое зна чение, влево или вправо на заданную величину. Для этой цели в C# определены два приведенных ниже оператора сдвига двоичных разрядов. << Сдвиг влево >> Сдвиг вправо
Ниже приведена общая форма для этих операторов: значение << число_битов значение >> число_битов
где число_битов — это число двоичных разрядов, на которое сдвигается указанное значение.
При сдвиге влево все двоичные разряды в указываемом значении сдвигаются на одну позицию влево, а младший разряд сбрасывается в нуль. При сдвиге вправо все двоичные разряды в указываемом значении сдвигаются на одну позицию вправо. Если вправо сдвигается целое значение без знака, то старший разряд сбрасывается в нуль. А если вправо сдвигается целое значение со знаком, то разряд знака сохраняется. На помним, что для представления отрицательных чисел старший разряд целого числа устанавливается в 1. Так, если сдвигаемое значение является отрицательным, то при каждом сдвиге вправо старший разряд числа устанавливается в 1. А если сдвигаемое значение является положительным, то при каждом сдвиге вправо старший разряд чис ла сбрасывается в нуль.
При сдвиге влево и вправо крайние двоичные разряды теряются. Восстановить по терянные при сдвиге двоичные разряды нельзя, поскольку сдвиг в данном случае не является циклическим.
Ниже приведен пример программы, наглядно демонстрирующий действие сдвига влево и вправо. В данном примере сначала задается первоначальное целое значение, равное 1. Это означает, что младший разряд этого значения установлен. Затем это це лое значение сдвигается восемь раз подряд влево. После каждого сдвига выводятся во семь младших двоичных разрядов данного значения. Далее процесс повторяется, но на этот раз 1 устанавливается на позиции восьмого разряда, а по существу, задается целое значение 128, которое затем сдвигается восемь раз подряд вправо. // Продемонстрировать применение операторов сдвига. using System; class ShiftDemo { static void Main { int val = 1; for(int i = 0; i < 8; i++) { for(int t=128; t > 0; t = t/2) { if((val & t) != 0) Console.Write("1 "); if((val & t) == 0) Console.Write("0 "); } Console.WriteLine; val = val << 1; // сдвиг влево } Console.WriteLine; val = 128; for(int i = 0; i < 8; i++) { for(int t=128; t > 0; t = t/2) { if((val & t) != 0) Console.Write("1 "); if((val & t) == 0) Console.Write("0 "); } Console.WriteLine; val = val >> 1; // сдвиг вправо } } }
Результат выполнения этой программы выглядит следующим образом. 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1
Двоичные разряды соответствуют форме представления чисел в степени 2, и поэто му операторы сдвига могут быть использованы для умножения или деления целых значений на 2. Так, при сдвиге вправо целое значение удваивается, а при сдвиге вле во — уменьшается наполовину. Разумеется, все это справедливо лишь в том случае, если крайние разряды не теряются при сдвиге в ту или иную сторону. Ниже приведен соответствующий пример. // Применить операторы сдвига для умножения и деления на 2. using System; class MultDiv { static void Main { int n; n = 10; Console.WriteLine("Значение переменной n: " + n); // Умножить на 2. n = n << 1; Console.WriteLine("Значение переменной n после " + "операции n = n * 2: " + n); // Умножить на 4. n = n << 2; Console.WriteLine("Значение переменной n после " + "операции n = n * 4: " + n); // Разделить на 2. n = n >> 1; Console.WriteLine("Значение переменной n после " + "операции n = n / 2: " + n); // Разделить на 4. n = n >> 2; Console.WriteLine("Значение переменной n после " + "операции n = n / 4: " + n); Console.WriteLine; // Установить переменную n в исходное состояние. n = 10; Console.WriteLine("Значение переменной n: " + n); // Умножить на 2 тридцать раз. n = n << 30; // данные теряются Console.WriteLine("Значение переменной п после " + "сдвига на 30 позиций влево: " + n); } }
Ниже приведен результат выполнения этой программы. Значение переменной n: 10 Значение переменной n после операции n = n * 2: 20 Значение переменной n после операции n = n * 4: 80 Значение переменной n после операции n = n / 2: 40 Значение переменной n после операции n = n / 4: 10 Значение переменной n: 10 Значение переменной n после сдвига на 30 позиций влево: -2147483648
Обратите внимание на последнюю строку приведенного выше результата. Когда целое значение 10 сдвигается влево тридцать раз подряд, информация теряется, по скольку двоичные разряды сдвигаются за пределы представления чисел для типа int. В данном случае получается совершенно "непригодное" значение, которое оказывается к тому же отрицательным, поскольку в результате сдвига в старшем разряде, исполь зуемом в качестве знакового, оказывается 1, а следовательно, данное числовое значение должно интерпретироваться как отрицательное. Этот пример наглядно показывает, что применять операторы сдвига для умножения иди деления на 2 следует очень акку ратно. (Подробнее о типах данных со знаком и без знака см. в главе 3.) Поразрядные составные операторы присваивания
Все двоичные поразрядные операторы могут быть использованы в составных опе рациях присваивания. Например, в двух приведенных ниже операторах переменной х присваивается результат выполнения операции исключающее ИЛИ над первона чальным значением переменной х и числовым значением 127. х = х ^ 127; х ^= 127; Оператор ?
Оператор ? относится к числу самых примечательных в С#. Он представляет со бой условный оператор и часто используется вместо определенных видов конструкций if-then-else. Оператор ? иногда еще называют тернарным, поскольку для него тре буются три операнда. Ниже приведена общая форма этого оператора. Выражение! ? Выражение2 : Выражение3;