1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 18
Текст из файла (страница 18)
Язык C#}}}}Console.WriteLine("p равно " + p + ", q равно " + q);if(!p | q)Console.WriteLine("Результат импликации " +p + " и " + q + " равен " + true);Console.WriteLine();Результат выполнения этой программы выглядит так:p равно True, q равно TrueРезультат импликации True и True равен Truep равно True, q равно Falsep равно False, q равно TrueРезультат импликации False и True равен Truep равно False, q равно FalseРезультат импликации False и False равен TrueСокращенные логические операторыC# поддерживает специальные сокращенные (short-circuit) версии логическихоператоров И и ИЛИ, которые можно использовать для создания более эффективного кода.Вспомним, что, если в операции И один операнд имеет значение ЛОЖЬ, результат будетложным независимо от того, какое значение имеет второй операнд.
А если в операции ИЛИодин операнд имеет значение ИСТИНА, результат будет истинным независимо от того,какое значение имеет второй операнд. Таким образом, в этих двух случаях вычислятьвторой операнд не имеет смысла. Если не вычисляется один из операндов, тем самымэкономится время и создается более эффективный код.Сокращенный оператор И обозначается символом &&, а сокращенный оператор ИЛИ— символом || (их обычные версии обозначаются одинарными символами & и |,соответственно).
Единственное различие между обычной и сокращенной версиями этихоператоров состоит в том, что при использовании обычной операции всегда вычисляютсяоба операнда, в случае же сокращенной версии второй операнд вычисляется только принеобходимости.Рассмотрим программу, в которой демонстрируется использование сокращенногооператора И. Программа определяет, является ли значение переменной d множителем числаn.
Здесь используется операция деления по модулю. Если остаток от деления d / n равеннулю, значит, d — множитель числа n. Чтобы не допустить ошибки деления на нуль,используется сокращенная форма оператора И.// Демонстрация использования сокращенных операторовusing System;class SCops {public static void Main() {int n, d;n = 10;d = 2;if(d != 0 && (n % d) == 0)Глава 4. Операторы87Console.WriteLine(d + " — множитель числа " + n);d = 0; // Теперь установим d равным нулю.// Поскольку d равно нулю,// второй операнд не вычисляется.if(d != 0 && (n % d) == 0)Console.WriteLine(d + " — множитель числа " + n);}}/* Теперь попробуем проделать то же самое безсокращенного оператора.
Такая попытка приведет к ошибке(деление на нуль). */if(d != 0 & (n % d) == 0)Console.WriteLine(d + " -- множитель числа " + n);Чтобы не допустить деления на нуль, в инструкции if сначала проверяется значениепеременной d на равенство нулю. Если наши опасения окажутся ненапрасными,выполнение сокращенного оператора И на этом прекратится. В первой проверке, когдапеременная d содержит число 2, операция деления по модулю выполняется. Втораяпроверка (а ей предшествует принудительная установка переменной d нулем) показывает,что второй операнд вычислять не имеет смысла, поэтому деление на нуль опускается.Попытка заменить сокращенный оператор И обычным заставит вычислить оба оператора и,как следствие, приведет к ошибке деления на нуль.Поскольку сокращенные формы операторов И и ИЛИ в некоторых случаях работаютэффективнее своих обычных “коллег”, читатель мог бы задать вполне резонный вопрос:“Почему бы компилятору C# вообще не отказаться от обычных форм этих операторов?”.Дело в том, что иногда необходимо, чтобы вычислялись оба операнда, поскольку вас могутинтересовать побочные эффекты вычислений.
Чтобы прояснить ситуацию, рассмотримследующую программу:// Демонстрация важности побочных эффектов.using System;class SideEffects {public static void Main() {int i;i = 0;}88}/* Здесь значение i инкрементируется, несмотря на то,что инструкция выполнена не будет. */if(false & (++i < 100))Console.WriteLine("Этот текст не будет выведен.");Console.WriteLine("Инструкция if выполнена: " + i); // Отображает: 1/* В этом случае значение i не инкрементируется, посколькусокращенный оператор И опускает инкрементирование. */if(false && (++i < 100))Console.WriteLine("Этот текст не будет выведен.");Console.WriteLine("Инструкция if выполнена: " + i); // По-прежнему 1 !!Часть I. Язык C#Как поясняется в комментариях, в первой if-инструкции значение переменной iинкрементируется независимо от результата выполнения самой if-инструкции. Но прииспользовании сокращенной версии оператора И во второй if-инструкции значениепеременной i не инкрементируется, поскольку первый операнд имеет значение false.
Изэтого примера вы должны извлечь следующий урок. Если в программе предполагаетсяобязательное выполнение правого операнда операции И/ИЛИ, вы должны использоватьполную, или обычную, форму этих операторов, а не сокращенную.И еще одна терминологическая деталь. Сокращенный оператор И также называетсяусловным И, а сокращенный ИЛИ — условным ИЛИ.Оператор присваиванияС оператором присваивания мы “шапочно” познакомились в главе 2. Теперь пришловремя для более официального знакомства. Оператор присваивания обозначаетсяодинарным знаком равенства (=). Его роль в языке C# во многом такая же, как и в другихязыках программирования.
Общая форма записи оператора присваивания имеет следующийвид.переменная = выражение;Здесь тип элемента переменная должен быть совместим с типом элементавыражение. Оператор присваивания интересен тем, что позволяет создавать целуюцепочку присвоений. Рассмотрим, например, следующий фрагмент кода.int x, y, z; x = y = z = 100;//Устанавливаем переменные x, y// и z равными 100.В этом фрагменте значения переменных x, y и z устанавливаются равными 100 водной инструкции. Эта инструкция успешно работает благодаря тому, что операторприсваивания генерирует значение правостороннего выражения.
Это значит, что значениевыражения z = 100 равно числу 100, которое затем присваивается переменной y, послечего в свою очередь присваивается переменной x. Использование цепочки присвоений —простой способ установить группу переменных равными одному (общему для всех)значению.Составные операторы присваиванияВ C# предусмотрены специальные составные операторы присваивания, которыеупрощают программирование определенных инструкций присваивания.
Лучше всего начатьс примера. Рассмотрим следующую инструкцию:x = x + 10;Используя составной оператор присваивания, ее можно переписать в таком виде:x += 10;Пара операторов += служит указанием компилятору присвоить переменной x суммутекущего значения переменной x и числа 10. А вот еще один пример.
Инструкцияx = x - 100;аналогична такой:x -= 100;Обе эти инструкции присваивают переменной x ее прежнее значение, уменьшенноена 100.Глава 4. Операторы89Составные версии операторов присваивания существуют для всех бинарныхоператоров (т.е. для всех операторов, которые работают с двумя операндами). Общая формаих записи такова:переменная op = выражение;Здесь элемент op означает конкретный арифметический или логический оператор,объединяемый с оператором присваивания.Возможны следующие варианты объединения операторов.+=-=*=/=%=&=|=^=Поскольку составные операторы присваивания выглядят короче своих несоставныхэквивалентов, то составные версии часто называют укороченными операторамиприсваивания.Составные операторы присваивания обладают двумя заметными достоинствами.
Вопервых, они компактнее своих “длинных” эквивалентов. Во-вторых, их наличие приводит ксозданию более эффективного кода (поскольку операнд в этом случае вычисляется толькоодин раз). Поэтому в профессионально написанных Сопрограммах вы часто встретитеименно составные операторы присваивания.Поразрядные операторыВ C# предусмотрен набор поразрядных операторов, которые расширяют областиприложения языка C#.
Поразрядные операторы действуют непосредственно на разрядысвоих операндов. Они определены только для целочисленных операндов и не могут бытьиспользованы для операндов типа bool, float или double.Поразрядные операторы предназначены для тестирования, установки или сдвигабитов (разрядов), из которых состоит целочисленное значение. Поразрядные операторыочень часто используются для решения широкого круга задач программированиясистемного уровня, например, при опросе информации о состоянии устройства или ееформировании. Поразрядные операторы перечислены в табл.
4.1.Таблица 4.1. Поразрядные операторыОператорЗначение&|^>><<~Поразрядное ИПоразрядное ИЛИПоразрядное исключающее ИЛИСдвиг вправоСдвиг влевоДополнение до 1 (унарный оператор НЕ)Поразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕПоразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕ обозначаются символами&, |, ^ и ~, соответственно.
Они выполняют те же операции, что и их логическиеэквиваленты, описанные выше. Различие состоит лишь в том, что поразрядные операцииработают на побитовой основе. В следующей таблице показан результат выполнениякаждой поразрядной операции для всех возможных сочетаний операндов (нулей и единиц).90Часть I. Язык C#pqp&qp|qp^q~p010100110001011101101010Поразрядный оператор И можно представить как способ подавления битовойинформации. Это значит, что 0 в любом операнде обеспечит установку в 0соответствующего бита результата.
Вот пример:1101 00111010 1010& ________1000 0010В следующей программе демонстрируется использование поразрядного оператора &для получения четных чисел из нечетных. Это реализуется посредством подавления(установки в нуль) младшего разряда числа. Например, число 9 в двоичном кодепредставляется числом 0000 1001. После обнуления младшего разряда получается число 8(0000 1000 в двоичном коде).// использование поразрядного оператора И для// "превращения" любого числа в четное.using System;class MakeEven {public static void Main() {ushort num;ushort i;for(i = 1; i <= 10; i++) {num = i;Console.WriteLine("num: " + num);num = (ushort) (num & 0xFFFE); // num & 1111 1110Console.WriteLine("num после сброса младшего бита: "+ num + "\n");}}}Результат выполнения этой программы имеет следующий вид:num: 1num после сброса младшего бита: 0num: 2num после сброса младшего бита: 2num: 3num после сброса младшего бита: 2num: 4num после сброса младшего бита: 4num: 5Глава 4.