Текст книги "Полное руководство. С# 4.0"
Автор книги: Герберт Шилдт
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 6 (всего у книги 58 страниц)
Без приведения типов результат сложения операндов ch1 и ch2 будет иметь тип int, и поэтому его нельзя присвоить переменной типа char.
Продвижение типов происходит и при выполнении унарных операций, например с унарным минусом. Операнды унарных операций более мелкого типа, чем int(byte, sbyte, short и ushort), т.е. с более узким диапазоном представления чисел, про двигаются к типу int. То же самое происходит и с операндом типа char. Кроме того, если выполняется унарная операция отрицания значения типа uint, то результат про двигается к типу long. Приведение типов в выражениях
Приведение типов можно применять и к отдельным частям крупного выражения. Это позволяет точнее управлять преобразованиями типов при вычислении выраже ния. Рассмотрим следующий пример программы, в которой выводятся квадратные корни чисел от 1 до 10 и отдельно целые и дробные части каждого числового результа та. Для этого в данной программе применяется приведение типов, благодаря которо му результат, возвращаемый методом Math.Sqrt(), преобразуется в тип int. // Пример приведения типов в выражениях. using System; class CastExpr { static void Main() { double n; for(n = 1.0; n <= 10; n++) { Console.WriteLine("Квадратный корень из {0} равен {1}", n, Math.Sqrt(n)); Console.WriteLine("Целая часть числа: (0)", (int) Math.Sqrt(n)); Console.WriteLine("Дробная часть числа: (0)", Math.Sqrt(n) – (int) Math.Sqrt(n) ); Console.WriteLine(); } } }
Вот как выглядит результат выполнения этой программы. Квадратный корень из 1 равен 1 Целая часть числа: 1 Дробная часть числа: 0 Квадратный корень из 2 равен 1.4142135623731 Целая часть числа: 1 Дробная часть числа: 0.414213562373095 Квадратный корень из 3 равен 1.73205080756888 Целая часть числа: 1 Дробная часть числа: 0.732050807568877 Квадратный корень из 4 равен 2 Целая часть числа: 2 Дробная часть числа: 0 Квадратный корень из 5 равен 2.23606797749979 Целая часть числа: 2 Дробная часть числа: 0.23606797749979 Квадратный корень из 6 равен 2.44948974278318 Целая часть числа: 2 Дробная часть числа: 0.449489742783178 Квадратный корень из 7 равен 2.64575131106459 Целая часть числа: 2 Дробная часть числа: 0.645751311064591 Квадратный корень из 8 равен 2.82842712474619 Целая часть числа: 2 Дробная часть числа: 0.82842712474619 Квадратный корень из 9 равен 3 Целая часть числа: 3 Дробная часть числа: 0 Квадратный корень из 10 равен 3.16227766016838 Целая часть числа: 3 Дробная часть числа: 0.16227766016838
Как видите, приведение результата, возвращаемого методом Math.Sqrt(), к типу int позволяет получить целую часть числа. Так, в выражении Math.Sqrt(n) – (int) Math.Sqrt(n)
приведение к типу int дает целую часть числа, которая затем вычитается из всего числа, а в итоге получается дробная его часть. Следовательно, результат вычисления данного выражения имеет тип double. Но к типу int приводится только значение, возвращаемое вторым методом Math.Sqrt().
ГЛАВА 4. Операторы
В языке C# предусмотрен обширный ряд операторов, предоставляющих программирующему возможность полного контроля над построением и вычислением выражений. Большинство операторов в С# относится к сле дующим категориям: арифметические, поразрядные, логиче ские и операторы отношения. Все перечисленные категории операторов рассматриваются в этой главе. Кроме того, в C# предусмотрен ряд других операторов для особых случаев, включая индексирование массивов, доступ к членам класса и обработку лямбда-выражений. Эти специальные опера торы рассматриваются далее в книге вместе с теми сред ствами, в которых они применяются. Арифметические операторы
Арифметические операторы, представленные в языке С#, приведены ниже. Оператор Действие + Сложение – Вычитание, унарный минус * Умножение / Деление % Деление по модулю – Декремент ++ Инкремент
Операторы +, -, * и / действуют так, как предполагает их обозначение. Их можно применять к любому встроенному числовому типу данных.
Действие арифметических операторов не требует особых пояснений, за исключени ем следующих особых случаев. Прежде всего, не следует забывать, что когда оператор / применяется к целому числу, то любой остаток от деления отбрасывается; например, результат целочисленного деления 10/3 будет равен 3. Остаток от этого деления можно получить с помощью оператора деления по модулю (%), который иначе называется оператором вычисления остатка. Он дает остаток от целочисленного деления. Напри мер, 10 % 3 равно 1. В C# оператор % можно применять как к целочисленным типам данных, так и к типам с плавающей точкой. Поэтому 10.0 % 3.0 также равно 1. В этом отношении C# отличается от языков С и C++, где операции деления по модулю разрешаются только для целочисленных типов данных. В приведенном ниже примере программы демонстрируется применение оператора деления по модулю. // Продемонстрировать применение оператора %. using System; class ModDemo { static void Main() { int iresult, irem; double dresult, drem; iresult = 10 / 3; irem = 10 % 3; dresult = 10.0 / 3.0; drem = 10.0 % 3.0; Console.WriteLine("Результат и остаток от деления 10/3: " + iresult + " " + irem); Console.WriteLine("Результат и остаток от деления 10.0 / 3.0: " + dresult + " " + drem); } }
Результат выполнения этой программы приведен ниже. Результат и остаток от деления 10 / 3: 3 1 Результат и остаток от деления 10.0 / 3.0: 3.33333333333333 1
Как видите, обе операции, % целочисленного типа и с плавающей точкой, дают один и тот же остаток, равный 1. Операторы инкремента и декремента
Операторы инкремента (++) и декремента (–) были представлены в главе 2. Как станет ясно в дальнейшем, они обладают рядом особых и довольно интересных свойств. Но сначала выясним основное назначение этих операторов.
Оператор инкремента увеличивает свой операнд на 1, а оператор декремента уменьшает операнд на 1. Следовательно, оператор х++;
равнозначен оператору х = x + 1;
а оператор х–;
равносилен оператору х = х – 1;
Следует, однако, иметь в виду, что в инкрементной или декрементной форме зна чение переменной х вычисляется только один, а не два раза. В некоторых случаях это позволяет повысить эффективность выполнения программы.
Оба оператора инкремента и декремента можно указывать до операнда (в префикс ной форме) или же после операнда (в постфиксной форме). Например, оператор х = х + 1;
может быть записан в следующем виде: ++х; // префиксная форма
или же в таком виде: х++; // постфиксная форма
В приведенном выше примере форма инкремента (префиксная или постфиксная) особого значения не имеет. Но если оператор инкремента или декремента использу ется в длинном выражении, то отличие в форме его записи уже имеет значение. Когда оператор инкремента или декремента предшествует своему операнду, то результатом операции становится значение операнда после инкремента или декремента. А когда оператор инкремента или декремента следует после своего операнда, то результатом операции становится значение операнда до инкремента или декремента. Рассмотрим следующий фрагмент кода. х = 10; у = ++х;
В данном случае значение переменной у будет установлено равным 11, поскольку значение переменной х сначала увеличивается на 1, а затем присваивается переменной у. Но во фрагменте кода х = 10; у = х++;
значение переменной у будет установлено равным 10, так как в этом случае значение переменной х сначала присваивается переменной у, а затем увеличивается на 1. В обо их случаях значение переменной х оказывается равным 11. Отличие состоит лишь том, когда именно это значение станет равным 11: до или после его присваивания пере менной у.
Возможность управлять моментом инкремента или декремента дает немало пре имуществ при программировании. Обратимся к следующему примеру программы, в которой формируется последовательный ряд чисел. // Продемонстрировать отличие между префиксной // и постфиксной формами оператора инкремента (++). using System; class PrePostDemo { static void Main() { int x, y; int i; x = 1; У = 0; Console.WriteLine("Ряд чисел, полученных " + "с помощью оператора у = у + х++;"); for(i = 0; i < 10; i++) { у = у + х++; // постфиксная форма оператора ++ Console.WriteLine(у + " "); } Console.WriteLine(); x = 1; У = 0; Console.WriteLine("Ряд чисел, полученных " + "с помощью оператора у = у + ++х;"); for(i = 0; i < 10; i++) { у = у + ++х; // префиксная форма оператора ++ Console.WriteLine(у + " "); } Console.WriteLine(); } }
Выполнение этой программы дает следующий результат. Ряд чисел, полученных с помощью оператора у = у + х++ 1 3 6 10 15 14 21 28 36 45 55 Ряд чисел, полученных с помощью оператора у = у + ++х; 2 5 9 14 20 27 35 44 54 65
Как подтверждает приведенный выше результат, в операторе у = у + х++;
первоначальное значение переменной х складывается с самим собой, а полученный результат присваивается переменной у. После этого значение переменной х увеличи вается на 1. Но в операторе у = у + ++х;
значение переменной х сначала увеличивается на 1, затем складывается с первоначаль ным значением этой же переменной, а полученный результат присваивается пере менной у. Как следует из приведенного выше результата, простая замена префиксной формы записи оператора ++х постфиксной формой х++ приводит к существенному изменению последовательного ряда получаемых чисел.
И еще одно замечание по поводу приведенного выше примера: не пугайтесь выра жений, подобных следующему: у + ++x
Такое расположение рядом двух операторов может показаться не совсем привыч ным, но компилятор воспримет их в правильной последовательности. Нужно лишь запомнить, что в данном выражении значение переменной у складывается с увеличен ным на 1 значением переменной х. Операторы отношения и логические операторы
В обозначениях оператор отношения и логический оператор термин отношения озна чает взаимосвязь, которая может существовать между двумя значениями, а термин логический – взаимосвязь между логическими значениями "истина" и "ложь". И по скольку операторы отношения дают истинные иди ложные результаты, то они неред ко применяются вместе с логическими операторами. Именно по этой причине они и рассматриваются совместно в данном разделе.
Ниже перечислены операторы отношения. Оператор Значение == Равно != Не равно > Больше < Меньше > Больше или равно <= Меньше или равно
К числу логических относятся операторы, приведенные ниже.
Результатом выполнения оператора отношения или логического оператора являет ся логическое значение типа bool.
В целом, объекты можно сравнивать на равенство или неравенство, используя опе раторы отношения == и !=. А операторы сравнения <, >, <= или >= могут применяться только к тем типам данных, которые поддерживают отношение порядка. Следователь но, операторы отношения можно применять ко всем числовым типам данных. Но зна чения типа bool могут сравниваться только на равенство или неравенство, поскольку истинные (true) и ложные (false) значения не упорядочиваются. Например, сравне ние true > false в C# не имеет смысла.
Операнды логических операторов должны относиться к типу bool, а результат вы полнения логической операции также относится к типу bool. Логические операторы &, |, ^ и ! поддерживают основные логические операции И, ИЛИ, исключающее ИЛИ и НЕ в соответствии с приведенной ниже таблицей истинности. p q p & q p | q p ^ q |P false false false false false true true false false true true false false true false true true true true true true true false false
Как следует из приведенной выше таблицы, результатом выполнения логической операции исключающее ИЛИ будет истинное значение (true), если один и только один ее операнд имеет значение true.
Ниже приведен пример программы, демонстрирующий применение нескольких операторов отношения и логических операторов. // Продемонстрировать применение операторов // отношения и логических операторов. using System; class RelLogOps { static void Main() { int i, j; bool b1, b2; i = 10; j = 11; if(i < j) Console.WriteLine("i < j"); if(i <= j) Console.WriteLine("i <= j"); if(i != j) Console.WriteLine("i != j"); if(i == j) Console.WriteLine("Нельзя выполнить"); if(i >= j) Console.WriteLine("Нельзя выполнить"); if(i > j) Console.WriteLine("Нельзя выполнить"); b1 = truer b2 = false; if(b1 & b2) Console.WriteLine("Нельзя выполнить"); if(!(b1 & b2)) Console.WriteLine("!(b1 & b2) – true"); if(b1 | b2) Console.WriteLine("b1 | b2 – true"); if(b1 ^ b2) Console.WriteLine("bl ^ b2 – true"); } }
Выполнение этой программы дает следующий результат. i < j i <= j i != j !(b1 & b2) – true b1 | b2 – true b1 ^ b2 – true
Логические операторы в C# выполняют наиболее распространенные логические операции. Тем не менее существует ряд операций, выполняемых по правилам фор мальной логики. Эти логические операции могут быть построены с помощью логиче ских операторов, поддерживаемых в С#. Следовательно, в C# предусмотрен такой на бор логических операторов, которого достаточно для построения практически любой логической операции, в том числе импликации. Импликация – это двоичная опера ция, результатом которой является ложное значение только в том случае, если левый ее операнд имеет истинное значение, а правый – ложное. (Операция импликации от ражает следующий принцип: истина не может подразумевать ложь.) Ниже приведена таблица истинности для операции импликации. p q Результат импликации p и q true true true true false false false false true false true true
Операция импликации может быть построена на основе комбинации логических операторов ! и |, как в приведенной ниже строке кода. !р | q
В следующем примере программы демонстрируется подобная реализация опера ции импликации. // Построение операции импликации в С#. using System; class Implication { static void Main() { bool p=false, q=false; int i, j; for(i = 0; i < 2; i++) { for(j = 0; j < 2; j++) { if(i==0) p = true; if(i==1) p = false; if(j==0) q = true; if(j==1) q = false; Console.WriteLine("p равно " + p + ", q равно " + q); if(!p | q) Console.WriteLine("Результат импликации " + p + " и " + q + " равен " + true); Console.WriteLine(); } } } }
Результат выполнения этой программы выглядит так. р равно True, q равно True Результат импликации True и True равен True р равно True, q равно False р равно False, q равно False Результат импликации False и True равен True р равно False, q равно False Результат импликации False и False равен True Укороченные логические операторы
В C# предусмотрены также специальные, укороченные, варианты логических опера торов И и ИЛИ, предназначенные для получения более эффективного кода. Поясним это на следующих примерах логических операций. Если первый операнд логической операции И имеет ложное значение (false), то ее результат будет иметь ложное зна чение независимо от значения второго операнда. Если же первый операнд логической операции ИЛИ имеет истинное значение (true), то ее результат будет иметь истинное значение независимо от значения второго операнда. Благодаря тому что значение вто рого операнда в этих операциях вычислять не нужно, экономится время и повышается эффективность кода.
Укороченная логическая операция И выполняется с помощью оператора &&, а уко роченная логическая операция ИЛИ – с помощью оператора ||. Этим укороченным логическим операторам соответствуют обычные логические операторы & и |. Един ственное отличие укороченного логического оператора от обычного заключается в том, что второй его операнд вычисляется только по мере необходимости.
В приведенном ниже примере программы демонстрируется применение укорочен ного логического оператора И. В этой программе с помощью операции деления по модулю определяется следующее: делится ли значение переменной d на значение пе ременной n нацело. Если остаток от деления n/d равен нулю, то n делится на d нацело. Но поскольку данная операция подразумевает деление, то для проверки условия деле ния на нуль служит укороченный логический оператор И. // Продемонстрировать применение укороченных логических операторов. using System; class SCops { static void Main() { int n, d; n = 10; d = 2; if (d ! = 0 && (n % d) == 0) Console.WriteLine(n + " делится нацело на " + d); d = 0; // задать нулевое значение переменной d // d равно нулю, поэтому второй операнд не вычисляется if (d != 0 && (n % d) == 0) Console.WriteLine(n + " делится нацело на " + d); // Если теперь попытаться сделать то же самое без укороченного // логического оператора, то возникнет ошибка из-за деления на нуль. if (d != 0 & (n % d) == 0) Console.WriteLine(n + " делится нацело на " + d); } }
Для исключения ошибки из-за деления на нуль в операторе if сначала проверяет ся условие: равно ли нулю значение переменной d. Если оно равно нулю, то на этом выполнение укороченного логического оператора И завершается, а последующая опе рация деления по модулю не выполняется. Так, при первой проверке значение пере менной d оказывается равным 2, поэтому выполняется операция деления по модулю. А при второй проверке это значение оказывается равным нулю, следовательно, опера ция деления по модулю пропускается, чтобы исключить деление на нуль. И наконец, выполняется обычный логический оператор И, когда вычисляются оба операнда. Если при этом происходит деление на нуль, то возникает ошибка при выполнении.
Укороченные логические операторы иногда оказываются более эффективными, чем их обычные аналоги. Так зачем же нужны обычные логические операторы И и ИЛИ? Дело в том, что в некоторых случаях требуется вычислять оба операнда логи ческой операции И либо ИЛИ из-за возникающих побочных эффектов. Рассмотрим следующий пример программы. // Продемонстрировать значение побочных эффектов. using System; class SideEffects { static void Main() { int i; bool someCondition = false; i = 0; // Значение переменной i инкрементируется, // несмотря на то, что оператор if не выполняется. if(someCondition & (++i < 100)) Console.WriteLine("He выводится"); Console.WriteLine("Оператор if выполняется: " + i); // выводится 1 // В данном случае значение переменной i не инкрементируется, // поскольку инкремент в укороченном логическом операторе опускается. if(someCondition && (++i < 100)) Console.WriteLine("He выводится"); Console.WriteLine("Оператор if выполняется: " + i); // по-прежнему 1 !! } }
Прежде всего обратим внимание на то, что переменная someCondition типа bool инициализируется значением false. Далее проанализируем каждый оператор if. Как следует из комментариев к данной программе, в первом операторе if перемен ная i инкрементируется, несмотря на то что значение переменной someCondition равно false. Когда применяется логический оператор &, как это имеет место в первом операторе if, выражение в правой части этого оператора вычисляется независимо от значения выражения в его левой части. А во втором операторе if применяется укоро ченный логический оператор. В этом случае значение переменной i не инкрементиру ется, поскольку левый операнд (переменная someCondition) имеет значение false, следовательно, выражение в правой части данного оператора пропускается. Из этого следует вывод: если в коде предполагается вычисление правого операнда логической операции И либо ИЛИ, то необходимо пользоваться неукороченными формами логи ческих операций, доступных в С#.
И последнее замечание: укороченный оператор И называется также условным логи ческим оператором И, а укороченный оператор ИЛИ – условным логическим оператором ИЛИ. Оператор присваивания
Оператор присваивания обозначается одиночным знаком равенства (=). В С# опера тор присваивания действует таким же образом, как и в других языках программирова ния. Ниже приведена его общая форма. имя_переменной = выражение
Здесь имя_переменной должно быть совместимо с типом выражения.
У оператора присваивания имеется одна интересная особенность, о которой вам будет полезно знать: он позволяет создавать цепочку операций присваивания. Рассмо трим, например, следующий фрагмент кода. int х, у, z; х = у = z = 100; // присвоить значение 100 переменным х, у и z
В приведенном выше фрагменте кода одно и то же значение 100 задается для пе ременных х, у и z с помощью единственного оператора присваивания. Это значение присваивается сначала переменной z, затем переменной у и, наконец, переменной х. Такой способ присваивания "по цепочке" удобен для задания общего значения целой группе переменных. Составные операторы присваивания
В C# предусмотрены специальные составные операторы присваивания, упрощаю щие программирование некоторых операций присваивания. Обратимся сначала к простому примеру. Приведенный ниже оператор присваивания х = х + 10;
можно переписать, используя следующий составной оператор присваивания. х += 10;
Пара операторов += указывает компилятору на то, что переменной х должно быть присвоено ее первоначальное значение, увеличенное на 10.
Рассмотрим еще один пример. Оператор х = х – 100;
и оператор x -= 100;
выполняют одни и те же действия. Оба оператора присваивают переменной х ее пер воначальное значение, уменьшенное на 100.
Для многих двоичных операций, т.е. операций, требующих наличия двух операн дов, существуют отдельные составные операторы присваивания. Общая форма всех этих операторов имеет следующий вид; имя_переменной ор = выражение
где ор – арифметический или логический оператор, применяемый вместе с операто ром присваивания.
Ниже перечислены составные операторы присваивания для арифметических и ло гических операций. += -= *= /= %= &= |= ^=
Составные операторы присваивания записываются более кратко, чем их несо ставные эквиваленты. Поэтому их иногда еще называют укороченными операторами присваивания.
У составных операторов присваивания имеются два главных преимущества. Во– первых, они более компактны, чем их "несокращенные" эквиваленты. И во-вторых, они дают более эффективный исполняемый код, поскольку левый операнд этих операторов вычисляется только один раз. Именно по этим причинам составные операторы присва ивания чаще всего применяются в программах, профессионально написанных на С#. Поразрядные операторы
В C# предусмотрен ряд поразрядных операторов, расширяющих круг задач, для ре шения которых можно применять С#. Поразрядные операторы воздействуют на от дельные двоичные разряды (биты) своих операндов. Они определены только для цело численных операндов, поэтому их нельзя применять к данным типа bool, float или double.
Эти операторы называются поразрядными, поскольку они служат для проверки, установки или сдвига двоичных разрядов, составляющих целое значение. Среди про чего поразрядные операторы применяются для решения самых разных задач програм мирования на уровне системы, включая, например, анализ информации состояния устройства. Все доступные в C# поразрядные операторы приведены в табл. 4.1.
Таблица 4.1. Поразрядные операторы Оператор Значение & Поразрядное И | Поразрядное ИЛИ ^ Поразрядное исключающее ИЛИ > Сдвиг вправо << Сдвиг влево ~ Дополнение до 1 (унарный оператор НЕ) Поразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕ
Поразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕ обозначаются следую щим образом: &, |, ^ и ~. Они выполняют те же функции, что и их логические аналоги, рассмотренные выше. Но в отличие от логических операторов, поразрядные операто ры действуют на уровне отдельных двоичных разрядов. Ниже приведены результаты поразрядных операций с двоичными единицами и нулями. Р q р & q р | q р ^ q ~р 0 0 0 0 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 0 0
С точки зрения наиболее распространенного применения поразрядную операцию И можно рассматривать как способ подавления отдельных двоичных разрядов. Это означает, что если какой-нибудь бит в любом из операндов равен 0, то соответствую щий бит результата будет сброшен в 0. Например: 1101 0011 1010 1010 & __________ 1000 0010
В приведенном ниже примере программы демонстрируется применение пораз рядного оператора & для преобразования нечетных чисел в четные. Для этой цели достаточно сбросить младший разряд числа. Например, число 9 имеет следующий двоичный вид: 0000 1001. Если сбросить младший разряд этого числа, то оно станет числом 8, а в двоичной форме – 0000 1000. // Применить поразрядный оператор И, чтобы сделать число четным. using System; class MakeEven { static void Main() { ushort num; ushort i; for(i = 1; i <= 10; i++) { num = i; Console.WriteLine("num: " + num); num = (ushort) (num & 0xFFFE); Console.WriteLine("num после сброса младшего разряда: " + num + "n"); } } }
Результат выполнения этой программы приведен ниже. num: 1 num после сброса младшего разряда: 0 num: 2 num после сброса младшего разряда: 2 num: 3 num после сброса младшего разряда: 2 num: 4 num после сброса младшего разряда: 4 num: 5 num после сброса младшего разряда: 4 num: 6 num после сброса младшего разряда: 6 num: 7 num после сброса младшего разряда: 6 num: 8 num после сброса младшего разряда: 8 num: 9 num после сброса младшего разряда: 8 num: 10 num после сброса младшего разряда: 10
Шестнадцатеричное значение 0xFFFE, используемое в поразрядном операторе И, имеет следующую двоичную форму: 1111 1111 1111 1110. Таким образом, пораз рядная операция И оставляет без изменения все двоичные разряды в числовом значе нии переменной num, кроме младшего разряда, который сбрасывается в нуль. В итоге четные числа не претерпевают никаких изменений, а нечетные уменьшаются на 1 и становятся четными.
Поразрядным оператором И удобно также пользоваться для определения уста новленного или сброшенного состояния отдельного двоичного разряда. В следующем примере программы определяется, является ли число нечетным. // Применить поразрядный оператор И, чтобы определить, // является ли число нечетным. using System; class IsOdd { static void Main() { ushort num; num = 10; if((num & 1) == 1) Console.WriteLine("He выводится."); num = 11; if((num & 1) == 1) Console.WriteLine(num + " – нечетное число."); } }
Вот как выглядит результат выполнения этой программы. 11 – нечетное число.
В обоих операторах if из приведенной выше программы выполняется поразрядная операция И над числовыми значениями переменной num и 1. Если младший двоич ный разряд числового значения переменной num установлен, т.е. содержит двоичную 1, то результат поразрядной операции num & 1 оказывается равным 1. В противном случае он равен нулю. Поэтому оператор if может быть выполнен успешно лишь в том случае, если проверяемое число оказывается нечетным.
Возможностью проверять состояние отдельных двоичных разрядов с помощью по разрядного оператора & можно воспользоваться для написания программы, в которой отдельные двоичные разряды проверяемого значения типа byte приводятся в двоич ной форме. Ниже показан один из способов написания такой программы. // Показать биты, составляющие байт. using System; class ShowBits { static void Main() { int t; byte val; val = 123; for (t=l28; t > 0; t = t/2) { if((val & t) != 0) Console.Write("1 "); if((val & t) == 0) Console.Write("0 "); } } }
Выполнение этой программы дает следующий результат. 0 1 1 1 1 0 1 1
В цикле for из приведенной выше программы каждый бит значения переменной val проверяется с помощью поразрядного оператора И, чтобы выяснить, установлен ли этот бит или сброшен. Если он установлен, то выводится цифра 1, а если сброшен, то выводится цифра 0.
Поразрядный оператор ИЛИ может быть использован для установки отдельных дво ичных разрядов. Если в 1 установлен какой-нибудь бит в любом из операндов этого опе ратора, то в 1 будет установлен и соответствующий бит в другом операнде. Например: 1101 0011 1010 1010 | __________ 1111 1011
Используя поразрядный оператор ИЛИ, можно без особого труда превратить упо минавшийся выше пример программы, преобразующей нечетные числа в четные, в приведенный ниже обратный пример, где четные числа преобразуются в нечетные. // Применить поразрядный оператор ИЛИ, чтобы сделать число нечетным. using System; class MakeOdd { static void Main() { ushort num; ushort i; for(i = 1; i <= 10; i++) { num = i; Console.WriteLine("num: " + num); num = (ushort) (num | 1); Console.WriteLine("num после установки младшего разряда: " + num + "n"); } } }
Результат выполнения этой программы выглядит следующим образом. num: 1 num после установки младшего разряда: 1 num: 2 num после установки младшего разряда: 3 num: 3 num после установки младшего разряда: 3 num: 4 num после установки младшего разряда: 5 num: 5 num после установки младшего разряда: 5 num: 6 num после установки младшего разряда: 7 num: 7 num после установки младшего разряда: 7 num: 8 num после установки младшего разряда: 9 num: 9 num после установки младшего разряда: 9 num: 10 num после установки младшего разряда: 11
В приведенной выше программе выполняется поразрядная операция ИЛИ над каждым числовым значением переменной num и 1, поскольку 1 дает двоичное значе ние, в котором установлен младший разряд. В результате поразрядной операции ИЛИ над 1 и любым другим значением младший разряд последнего устанавливается, тогда как все остальные разряды остаются без изменения. Таким образом, результирующее числовое значение получается нечетным, если исходное значение было четным.
Поразрядный оператор исключающее ИЛИ устанавливает двоичный разряд опе ранда в том и только в том случае, если двоичные разряды сравниваемых операндов оказываются разными, как в приведенном ниже примере. 0111 1111 1011 1001 ^ __________ 1100 0110
У поразрядного оператора исключающее ИЛИ имеется одно интересное свойство, которое оказывается полезным в самых разных ситуациях. Так, если выполнить снача ла поразрядную операцию исключающее ИЛИ одного значения X с другим значением Y, а затем такую же операцию над результатом предыдущей операции и значением Y, то вновь получится первоначальное значение X. Это означает, что в приведенном ниже фрагменте кода R1 = X ^ Y; R2 = R1 ^ Y;
значение переменной R2 оказывается в итоге таким же, как и значение переменной X. Следовательно, в результате двух последовательно выполняемых поразрядных опера ций исключающее ИЛИ, в которых используется одно и то же значение, подучается первоначальное значение. Этим свойством данной операции можно воспользоваться для написания простой программы шифрования, в которой некоторое целое значение служит в качестве ключа для кодирования и декодирования сообщения с помощью операции исключающее ИЛИ над символами этого сообщения. В первый раз опера ция исключающее ИЛИ выполняется для кодирования открытого текста в зашифро ванный, а второй раз – для декодирования зашифрованного текста в открытый. Разу меется, такое шифрование не представляет никакой практической ценности, посколь ку оно может быть легко разгадано. Тем не менее оно служит интересным примером для демонстрации результатов применения поразрядных операторов исключающее ИЛИ, как в приведенной ниже программе. // Продемонстрировать применение поразрядного оператора исключающее ИЛИ. using System; class Encode { static void Main() { char ch1 = 'H'; char ch2 = 'i'; char ch3 = '!'; int key = 88; Console.WriteLine("Исходное сообщение: " + ch1 + ch2 + ch3); // Зашифровать сообщение. ch1 = (char) (ch1 ^ key); ch2 = (char) (ch2 ^ key); ch3 = (char) (ch3 ^ key); Console.WriteLine("Зашифрованное сообщение: " + ch1 + ch2 + ch3); // Расшифровать сообщение. ch1 = (char) (ch1 ^ key); ch2 = (char) (ch2 ^ key); ch3 = (char) (ch3 ^ key); Console.WriteLine("Расшифрованное сообщение: " + ch1 + ch2 + ch3); } }