|
Программирование >> Унарные и бинарные операторы
нительный код строится так, чтобы старший бит в двоичном представлении отрицательных чисел был равен единице. Тогда наибольшее по абсолютной величине отрицательное число будет равно в двоичном представлении 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 проис- Оператор ++ применим только к переменным, запись (а+Ь)++ бессмысленна.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |