Программирование >>  Унарные и бинарные операторы 

1 2 [ 3 ] 4 5 6 ... 37


нительный код строится так, чтобы старший бит в двоичном представлении отрицательных чисел был равен единице. Тогда наибольшее по абсолютной величине отрицательное число будет равно в двоичном представлении 1000, то есть -8 (подумайте, почему). Раз в четыре бита помещается восемь отрицательных чисел и ноль, а всего возможных комбинаций - 16, то остается место для 7 положительных чисел: 1,2,3,7.

Задача 3.3. Используйте знания о двоичном дополнительном коде, чтобы понять, какие числа можно хранить в переменной типа int, занимающей в памяти компьютера два, четыре, восемь байтов.

Задача 3.4. Используйте программу, показанную в листинге 3.3, для вычисления суммы чисел от 1 до 2 ООО ООО. Почему сумма получается отрицательной? Как с этим бороться?

После рассказа о беззнаковых переменных и принципах кодирования чисел со знаком мы в состоянии разобраться, что произойдет при смешении различных целочисленных переменных в одном выражении.

Прежде всего, нужно понять, что компилятор, пытаясь привести переменную одного типа к другому, по-надает в затруднительное, а подчас и безвыходное положение. Попробуем, например, вычесть из -1 единицу, причем отрицательное значение будем, как и положено, хранить в переменной со знаком, а единицу - в переменной типа unsigned (листинг 3.6).

Листинг 3.6

finclude <iostream> using namespace std; int main(){ unsigned iu=l; int is--l;

cout is-iu \n:

cout is-static cast<int>(iu) \n;

Ка-чалось бы, в программе, показанной в листинге 3.6, нет подвоха, и на экране должно появиться число -2 (именно такова разность -1 и 1). Но первая инструкция вывода показывает не -2, а 4 294 967 294 - большее положительное число, почти предельное для переменных типа unsigned int!

Так получается, потому что в языке С++ есть довольно сложные правила подтягивания одних переменных к другим. Если целочислегн1ая переменная подтягивается к типу double, никаких неожиданностей, как правило, не происходит. Но если компилятор встречает две целочисленные переменные - одну со знаком, другую без, правила гласят: переменную со знаком нужно подтянуть к переметюй без знака. В нашем случае это значит, что число -1, двоичное представление которого состоит, как мы знаем, из единиц во всех разрядах, превращается в большое положительное число, из которого вычитается единица. Вот мы и видим на экране 4 294 967 294 вместо -2. Чтобы получить желанные -2, нужно явно привести беззнаковое число к типу int, что и делается в последней строке программы. Тогда у компилятора не останется выбора, и программа покажет на экране ожидаемое число.

Полные правила преобразования переменных довольно сложны, по чап1е всего без них можно обойтись. Нужно только знать обпше принципы кодирования и преобразований (подтягивание узкого типа к более широкому ), а также стараться не смешивать целочисленные переменные со знаком и без знака.

Персменнто unsigned int можно для краткости объявить как просто unsigned iu-1.

Когда размеры обеих переменных (например, int и unsigned int) совпадают.



Умные операторы

Мы привыкли к тому, что арифметические операторы (+, -, *, /) применимы к числам, и хорошо знаем, что такое дважды два. Но оказывается, что в С++ один и тот же оператор имеет множество смыслов, поэтому арифметические операторы можно встретить там, где числами и не пахнет. Посмотрим, например, каков смысл сложения строк, представляющих собой последовательности символов: букв, пробелов, знаков препинания ИТ. д.

Строка - специальный объект языка С++, задаваемый словом string. Инструкция string s создает объект s типа string. Можно задать начаяьное значение строки, ука.зав последовательность символов в кавычках:

string 5= 3дравствуй :

Рассмотрим листинг 3.7.

Листинг 3.7

#include <iostreaffl> include <string> using namespace std: int main(){ string a.b.c; а= 3дравствуй ; Ь= Мана! : c=a + b:

cout с endl: if(a > b)

cout a endl: el se

cout b endl:

. }

Программа, показанная в листинге, имеет дело с тремя строками: а, b и с. Значения первых двух задаются явно (например, Ь= Мама! ;), а в третью строку отправляется сумма первых двух (с=а+Ь;). Но что значит прибавить к строке а строку Ь ? В языке С++ под этим по-

нимается дописывание строки b после строки а. То есть после сложения строк а и b в строке с оказывается их сумма, равная Здравствуй Мама! .

Возникает вопрос: как компилятор С++ узнает, что делать с объектами, соединенными знаком + (и любыми другими операторами)? Ответ зависит от типа объекта. Дело в том, что все объекты С++ равны, по некоторые равнее других . Самые равные - уже известные нам целочисленные нсрсмсннью, а также переменные типа doubl е. Они настолько глубоко укоренились в языке, что выдрать их оттуда невозможно. Встречая пе-ремегшые такого типа, компилятор знает, что делать, и ему не нужны файлы описания, включаемые директивой #include.

Другое дело - такие объекты, как cout и string. Перечень возможных операций, а также их смысл содержатся в описании этих объектов. Вот почему компилятор требует подключения файлов <iostream> (там описан объект cout) и <string> (там описаны объекты типа string).

Эти описания можно, в принципе, менять, задавая другой смысл сложения строк или выдумывая какие-то новые операции (умножения строк, например), но лучше такие эксперименты проводить над собственными объектами, не трогая объекты из стандартной библиотеки, такие как stri ng.

В следующей главе мы подробнее займемся строками, а в этой расскажем лишь о возможных операциях сравнения. В конце листинга 3.6 сравниваются две строки - а и Ь. Здесь применена чуть другая условная конструкция if о else. Если условие в круглых скобках (у нас - а < b ) истинно, выполняется инструкция, следующая за i f (в нашем случае cout а endl), если нет -инструкция после else (у нас - cout b endl).

На первый взгляд условие а < b кажется странным, Как будто сравниваются лампочка и апельсин. Нам



На первый взгляд условие а < b кажется странным, как будто сравниваются лампочка и апельсин. Нам понятно, что два меньше трех. Но что больше - Здравствуй или Мама! ? Ответ зависит от метода сравнения строк. Стандартные объекты типа string сравниваются лексикографически, то есть большей считается строка, у которой больше первый несовпа/1ающий символ. В нашем случае не совпадают уже первые символы строк 3 и М . Какой же из них больше? Очевидно, больше второй, потому что буквы, как правило, кодируются такими числами, чтобы большему числу соответствовало низшее положение в алфавитном списке. Символ М ниже по алфавиту, чем 3 , и, следовательно, больше. Значит, в результате выполнения условной инструкции if О на экране появится строка Мама! .

Конечно, строки можно.сравнивать и другими способами, например по длине, но лексикографическое сравнение - самое разумное, потому что позволяет расставить строки в алфавитном порядке, как в словаре.

Унарные и бинарные операторы

Эти мудреные названия означают всего лишь, что есть операторы, работающие с одним объектом (унарные) и с двумя (бинарные). Нам встречались те и другие. Например, оператор сложения + - бинарный, поскольку слагаемых всегда два, а оператор приведения типа static casto() - унарный (почему - догадайтесь сами).

В этом разделе мы ггознакомимся с несколькими важными операторами, а поводом для изучения станет программа суммирования чисел из листинга 3.3. В ней встречается довольно неуклюжая инструкция sum=sum+i, смысл которой в увеличении переменной sum на вели-

чину i. Эта инструкция станет понятней, если записать ее с помощью нового оператора +=: sum+=i:

Естественно, все арифметические операторы позволяют использовать такую же запись, вместо х-х*а удобнее писать х*=а, вместо х=х/а следует писать х/=а и т. д. Новый оператор += можно применить и в инструкции увеличения i на единицу, записав ее как i+=l, но поскольку операция увеличения на единицу встречается очень часто, для нее придумали специальный оператор автоувеличения (++). То есть увеличение i на единицу можно записать как i=i+l, как i+=l или как i++. Последняя запись - самая короткая и попятная. Кроме автоувеличения есть, конечно, и автоуменьшение на единицу (-).

Знание новых операторов позволяет нам записать программу суммирования так, как показано в листинге 3.8.

Листинг 3.8

#include <iostrearo> using namespace std: int main(){ int N=1000: int sum=0.i=l; while(i<=N)

sum +=i++: cout suni= sum endl: }

Теперь в цикле whi le() всего одна инструкция, и фигурные скобки стали не нужны. Основная инструкция программы (sum+=i++:) выглядит довольно странно, но такая запись очень типична для С++, и к ней следует привыкнуть. При этом нужно знать, что оператор автоувеличения может стоять но разные стороны переменной. Если он стоит справа от i, то увеличение i проис-

Оператор ++ применим только к переменным, запись (а+Ь)++ бессмысленна.



1 2 [ 3 ] 4 5 6 ... 37

© 2006 - 2021 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика