1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 14
Текст из файла (страница 14)
все они увеличивают значение п на 1.Оператор инкремента достаточно странен, но еще больше странности добавляет емуто, что на самом деле имеется два оператора инкремента: + + п и п + + . Первый, + + п , называется префиксным, а второй, п + + , — постфиксным. Разница между ними достаточнотонкая, но очень важная.Вспомните, что каждое выражение имеет тип и значение.
В следующем фрагментеисходного текста и + + п , и п++ имеют тип int:int П;П = 1;int р = ++П;76Часть II. Основы программирования в С#n = 1;int m = n + + ;Чему равны значения p и m после выполнения этого фрагмента? (Подсказка: можновыбирать 1 или 2.) Оказывается, значение р равно 2, а значение m — 1. То есть значениевыражения + + п — это значение п после увеличения, а значение п + + равно значению пдо увеличения. Значение самой переменной п в обоих вариантах равно 2.Эквивалентныеоператорыдекремента—п- -и— п—используютсядлязамены выражения n = n - 1 .
Они работают точно так же, как и операторы инкремента.Откуда взялся оператор инкремента?Причина появления оператора инкремента лежит в туманном прошлом —в наличии в 1970-х годах в машине PDP-8 машинной команды инкремента.Язык С, прямой предок С#, в свое время создавался для применения именно на этихмашинах.
Наличие соответствующей машинной команды позволяло уменьшить количество машинных команд при использовании п + + вместо п=пч-1. В то время экономия даже нескольких машинных команд давала существенный выигрыш во времени работы.В настоящее время компиляторы гораздо интеллектуальнее, и нет никакой разницы,написать ли в программе п + + или п = п + 1 . Однако программисты — люди привычки,так что оператор инкремента благополучно дожил до сегодняшних дней, и увидетьв программе на С или С++ выражение п = п + 1 практически нереально.Кроме того, чаще всего программистами используется постфиксная версия оператора.Впрочем, это дело вкуса..
?С# предоставляет к услугам программиста также целый ряд логических операторовсравнения, показанных в табл. 4.3. Эти операторы называются логическими сравнениями(logical comparisons), поскольку они возвращают результат сравнения в виде значенияtrue или f a l s e , имеющего тип b o o l .• Вот примеры использования логических сравнений:int m = 5;int n = 6;bool b = m > n;В этом примере переменной b присваивается значение f a l s e , поскольку 5 не больше, чем 6.2Использование префиксного оператора инкремента дает определенный выигрыш(компилятору не приходится дополнительно хранить значение переменной до инкремента), такчто лучше приобретать привычку применять префиксную форму там, где выбор вида оператораинкремента не принципиален. — Примеч.
ред.Глава 4. Операторы77Т а б л и ц а 4.3. Л о г и ч е с к и е операторы сравненияОператор......возвращает true, если...а=.= Ьа имеет то же значение, что и ьа>ьа больше ьа>= bа больше или равно ьа меньше ьа< ь<= ьа!= Ьа не равно ьаа меньше или равно ьЛогические сравнения определены для всех числовых типов, включая f l o a t , doub l e , d e c i m a l и c h a r . Все приведенные ниже выражения корректны:bool b;b = 3 > 2;b = 3 . 0 > 2.0;1> 'b' ;b = 'ab =1A'1b =• ' A<'a';<'b' ;•//////////////////b = 10M > 12M;truetruef a l s e - позже в алфавитном порядкео з н а ч а е т "больше"true- п р о п и с н о е 'А' меньшестрочного ' а 'true- в с е п р о п и с н ы е буквы меньше в с е хстрочныхfalseОператоры сравнения всегда дают в качестве результата величину типа b o o l .
Операторы сравнения, отличные от ==, неприменимы к переменным тира s t r i n g (не волнуйтесь, С# предлагает другие способы сравнения строк).Сравнение чисел с плавающей точкойСравнение двух чисел с плавающей точкой может легко оказаться не вполне корректным, так что тут нужна особая осторожность. Рассмотрим следующее сравнение:floatfloatfl =f2 =boolfl =f2 =boolfl;f2;10;fl /Ы =9;fl /b2 =3;(3*f2)==fl;3;(3*f2)==fl;Обратите внимание, что в пятой и восьмой строках примера сначала содержится оператор присваивания =, а затем оператор сравнения ==. Это — разные операторы.С# сначала выполняет логическое сравнение, а затем присваивает его результат переменной слева от оператора присваивания.ЕдинственноеотличиемеждувычислениямиЫиЬ2состоитвисходномзначении f 1.
Так чему же равны значения Ы и Ь2? Очевидно, что значение Ы равноt r u e : 9/3 равно 3, 3*3 равно 9, 9 равно 9. Никаких проблем!Значение Ы не столь очевидно: 10/3 равно 3.3333.... 3.3333...*3 равно 9.9999.... Норавны ли числа 9.9999... и 10? Это зависит от того, насколько сообразительны ваши78Часть II. Основы программирования в С#компилятор и процессор. При использовании процессора типа Pentium С# недостаточноумен для того, чтобы понять, что Ы надо присвоить значение t r u e .Для сравнения f 1 и f 2 можно воспользоваться функцией для вычисления абсолютного значения следующим образом:Math.abs(fl-f2*3.0)<.0001;ности//.
. . и л и д р у г а я с т е п е н ь точТакая функция вернет значение t r u e в обоих случаях. Вместо . 0 0 0 1 можно использовать константу D o u b l e . E p s i l o n , чтобы получить максимальную точность. Эта константа представляет собой наименьшую возможную разницу между двумя неравнымизначениями типа d o u b l e .Чтобы узнать, какие еще возможности скрывает в себе класс S y s t e m . M a t h , вос1пользуйтесь командой меню H e l p ^ I n d e x и введите Math в поле L o o k For.Составные л о г и ч е с к и е о п е р а т о р ыДля переменных типа b o o l имеются специфичные для них операторы, показанныев табл.
4.4.Оператор ! представляет собой логический эквивалент знака "минус". Например,! а истинно, если а ложно, и ложно, если а истинно.Следующие два оператора тоже вполне просты и понятны. а&Ь истинно тогда и только тогда, когда и а, и b одновременно равны t r u e ; а | b истинно тогда и только тогда,Лкогда или а, или Ь, или оба они одновременно равны t r u e . Оператор(исключающееили) возвращает значение t r u e тогда и только тогда, когда значения а и b различны —т.е. когда одно из значений t r u e , а второе — f a l s e .Все перечисленные операторы возвращают в качестве результата значение типа b o o l .Операторы &,|иимеют версии, называющиеся побитовыми (bitwise). Приприменении к переменным типа i n t эти операторы выполняют действия с каждым битом отдельно.
Таким образом, 6&3 равно 2 ( 0 1 1 0 2 & 0 0 1 1 2 равно 0010 2 ),ЛЛ6 | 3 равно 7 ( 0 1 1 0 2 1 0 0 1 1 2 равно 0111 2 ), а 6 3 равно 5 ( 0 1 1 0 2 0 0 1 1 2 равно0101 2 ). Бинарная арифметика — очень интересная вещь, но она выходит за рамки настоящей книги.Последние два оператора очень похожи на предыдущие, но имеют одно едва уловимое отличие. В чем оно заключается, вы сейчас поймете. Рассмотрим следующий пример:bool b =(ЛогическоеВыражение!)Глава 4. Операторы&(ЛогическоеВьгражение2) ;79В этом случае С# вычисляет Л о г и ч е с к о е В ы р а ж е н и е 1 и ЛогическоеВыражение2,а затем смотрит, равны они оба t r u e или нет, чтобы найти, какое значение следует присвоить переменной Ь.
Но может оказаться, что С# выполняет лишнюю работу — ведьесли одно из выражений равно f a l s e , то каким бы ни было второе, результат не можетбыть t r u e в любом случае.Оператор && позволяет избежать вычисления второго выражения, если после вычисления первого конечный результат становится очевиден:bool Ь =(ЛогическоеВыражение1)&&(ЛогическоеВыражение2);В этой ситуации С# вычисляет значение Л о г и ч е с к о е В ы р а ж е н и е 1 , и если оно равноf a l s e , то переменной Ь присваивается значение f a l s e и Л о г и ч е с к о е В ы р а ж е н и е 2 невычисляется. Если же ЛогическоеВыражение1 равно t r u e , то С# вычисляет ЛогическоеВыражение2 и после этого определяет, какое значение присвоить переменной Ь.Оператор | | работает аналогично, как видно из следующего выражения:bool b =(ЛогическоеВыражение1)(ЛогическоеВыражение2);В этой ситуации С# вычисляет значение ЛогическоеВыражение1, и если оно равно t r u e ,то переменной b присваивается значение t r u e и ЛогическоеВыражение2 не вычисляется.
Если же ЛогическоеВыражение1 равно f a l s e , то С# вычисляет ЛогическоеВыражение2 и после этого определяет, какое значение присвоить переменной Ь.Вы можете называть эти операторы "сокращенным и" и "сокращенным или".В вычислениях тип результата важен не менее, чем сам результат. Рассмотрим следующее выражение:int П ;П = 5 * 5 + 7;Калькулятор утверждает, что результат вычислений равен 32.
Но это выражение имеет не только значение, но и тип.Будучи записано на "языке типов", оно принимает следующий вид:int [=] int * int + int;Для выяснения типа выражения нужно следовать тому же шаблону, что и при вычислении его значения. Умножение имеет более высокий приоритет, чем сложение. Умножение int на int дает int. Далее идет сложение int и int, что в результате тоже дает int. Итак, вычисление типа приведенного выражения происходит таким образом:int * int + intint + intintВычисление типа операцииВыяснение типа выражения происходит в нисходящем направлении посредством выяснения типов подвыражений.
Каждое выражение имеет тип, и типы левых и правых аргументов оператора должны соответствовать самому оператору:typel<ор>type2•=>type3(Здесь стрелка означает "дает".) Типы t y p e l и t y p e 2 должны быть совместимы с оператором о р .80Часть II. Основы программирования в С#Большинство операторов могут иметь несколько вариантов. Например, оператор умножения может быть следующих видов:intuintlongfloatdecimaldouble* int* uint* long* float* decimal* double•=><=>•=>•=><=>intuintlongfloatdecimaldoubleТаким образом, 2 * 3 использует i n t * i n t версию оператора * и дает в результатеint 6.Неявное преобразование типовВсе хорошо, просто и понятно, если умножать две переменные типа i n t или две переменные типа f l o a t .
Но что получится, если типы аргументов слева и справа будутразличны? Что, например, произойдет в следующей ситуации:int n l = 1 0 ;double d2 = 5 . 0 ;double d R e s u l t = nl*d2 ;Во-первых, в C# нет оператора умножения i n t * d o u b l e . C# может просто сгенерировать сообщение об ошибке и предоставить разбираться с проблемой программисту.Однако он пытается понять намерения программиста и помочь ему. У С# есть операторыумножения i n t * i n t и d o u b l e * d o u b l e . С# мог бы преобразовать d2 в значение i n t ,но такое преобразование привело бы к потере дробной части числа (цифр после десятичной точки).