Главная » Просмотр файлов » Бьерн Страуструп

Бьерн Страуструп (947334), страница 18

Файл №947334 Бьерн Страуструп (Стpаустpуп - Книга о C++) 18 страницаБьерн Страуструп (947334) страница 182013-09-15СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 18)

применяются "слева направо".

Э

____________________________________________________________

Операции С++ (продолжение)

============================================================

<< Сдвиг влево expr << expr

>> Сдвиг вправо expr >> expr

____________________________________________________________

< Меньше expr < expr

<= Меньше или равно expr <= expr

> Больше expr > expr

>= Больше или равно expr >= expr

____________________________________________________________

== Равно expr == expr

!= Не равно expr != expr

____________________________________________________________

& Поразрядное И expr & expr

____________________________________________________________

^ Поразрядное исключающее ИЛИ expr ^ expr

____________________________________________________________

| Поразрядное включающее ИЛИ expr | expr

____________________________________________________________

&& Логическое И expr && expr

____________________________________________________________

|| Логическое ИЛИ expr || expr

____________________________________________________________

? : Операция условия expr? expr : expr

____________________________________________________________

= Простое присваивание lvalue = expr

*= Присваивание с умножением lvalue *= expr

/= Присваивание с делением lvalue /= expr

%= Присваивание с взятием lvalue %= expr

остатка от деления

+= Присваивание со сложением lvalue += expr

-= Присваивание с вычитанием lvalue -= expr

<<= Присваивание со сдвигом влево lvalue <<= expr

>>= Присваивание со сдвигом вправо lvalue >>= expr

&= Присваивание с поразрядным И lvalue &= expr

|= Присваивание с поразрядным lvalue |= expr

включающим ИЛИ

^= Присваивание с поразрядным lvalue ^= expr

исключающим ИЛИ

____________________________________________________________

Запятая (последовательность) expr , expr

____________________________________________________________

3.2.1 Скобки

Синтаксис языка С++ перегружен скобками, и разнообразие их применений

способно сбить с толку. Они выделяют фактические параметры при

вызове функций, имена типов, задающих функции, а также служат для

разрешения конфликтов между операциями с одинаковым приоритетом.

К счастью, последнее встречается не слишком часто, поскольку приоритеты

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

"естественным образом" (т.е. наиболее распространенным образом).

Например, выражение

if (i<=0 || max<i) // ...

означает следующее: "Если i меньше или равно нулю, или если max меньше i".

То есть, оно эквивалентно

if ( (i<=0) || (max<i) ) // ...

но не эквивалентно допустимому, хотя и бессмысленному выражению

if (i <= (0||max) < i) // ...

Тем не менее, если программист не уверен в указанных правилах,

следует использовать скобки, причем некоторые предпочитают для

надежности писать более длинные и менее элегантные выражения, как:

if ( (i<=0) || (max<i) ) // ...

При усложнении подвыражений скобки используются чаще. Не надо, однако,

забывать, что сложные выражения являются источником ошибок. Поэтому,

если у вас появится ощущение, что в этом выражении нужны скобки,

лучше разбейте его на части и введите дополнительную переменную.

Бывают случаи, когда приоритеты операций не приводят к "естественному"

порядку вычислений. Например, в выражении

if (i&mask == 0) // ловушка! & применяется после ==

не происходит маскирование i (i&mask), а затем проверка результата

на 0. Поскольку у == приоритет выше, чем у &, это выражение эквивалентно

i&(mask==0). В этом случае скобки играют важную роль:

if ((i&mask) == 0) // ...

Имеет смысл привести еще одно выражение, которое вычисляется

совсем не так, как мог бы ожидать неискушенный пользователь:

if (0 <= a <= 99) // ...

Оно допустимо, но интерпретируется как (0<=a)<=99, и результат первого

сравнения равен или 0, или 1, но не значению a (если, конечно,

a не есть 1). Проверить, попадает ли a в диапазон 0...99, можно так:

if (0<=a && a<=99) // ...

Среди новичков распространена ошибка, когда в условии вместо ==

(равно) используют = (присвоить):

if (a = 7) // ошибка: присваивание константы в условии

// ...

Она вполне объяснима, поскольку в большинстве языков "=" означает "равно".

Для транслятора не составит труда сообщать об ошибках подобного рода.

3.2.2 Порядок вычислений

Порядок вычисления подвыражений, входящих в выражение, не всегда

определен. Например:

int i = 1;

v[i] = i++;

Здесь выражение может вычисляться или как v[1]=1, или как v[2]=1.

Если нет ограничений на порядок вычисления подвыражений, то транслятор

получает возможность создавать более оптимальный код. Транслятору

следовало бы предупреждать о двусмысленных выражениях, но к сожалению

большинство из них не делает этого.

Для операций

&& || ,

гарантируется, что их левый операнд вычисляется раньше правого операнда.

Например, в выражении b=(a=2,a+1) b присвоится значение 3. Пример

операции || был дан в $$3.2.1, а пример операции && есть в $$3.3.1.

Отметим, что операция запятая отличается по смыслу от той запятой, которая

используется для разделения параметров при вызове функций. Пусть есть

выражения:

f1(v[i],i++); // два параметра

f2( (v[i],i++) ) // один параметр

Вызов функции f1 происходит с двумя параметрами: v[i] и i++, но

порядок вычисления выражений параметров неопределен. Зависимость

вычисления значений фактических параметров от порядка вычислений

- далеко не лучший стиль программирования. К тому же программа

становится непереносимой.

Вызов f2 происходит с одним параметром, являющимся выражением,

содержащим операцию запятая: (v[i], i++). Оно эквивалентно i++.

Скобки могут принудительно задать порядок вычисления. Например,

a*(b/c) может вычисляться как (a*b)/c (если только пользователь

видит в этом какое-то различие). Заметим, что для значений с плавающей

точкой результаты вычисления выражений a*(b/c) и (a*b)/ могут

различаться весьма значительно.

3.2.3 Инкремент и декремент

Операция ++ явно задает инкремент в отличие от неявного его задания

с помощью сложения и присваивания. По определению ++lvalue означает

lvalue+=1, что, в свою очередь означает lvalue=lvalue+1 при условии,

что содержимое lvalue не вызывает побочных эффектов. Выражение,

обозначающее операнд инкремента, вычисляется только один раз. Аналогично

обозначается операция декремента (--). Операции ++ и -- могут

использоваться как префиксные и постфиксные операции. Значением ++x

является новое (т. е. увеличенное на 1) значение x. Например, y=++x

эквивалентно y=(x+=1). Напротив, значение x++ равно прежнему значению x.

Например, y=x++ эквивалентно y=(t=x,x+=1,t), где t - переменная того

же типа, что и x.

Напомним, что операции инкремента и декремента указателя

эквивалентны сложению 1 с указателем или вычитанию 1 из указателя, причем

вычисление происходит в элементах массива, на который настроен

указатель. Так, результатом p++ будет указатель на следующий элемент.

Для указателя p типа T* следующее соотношение верно по определению:

long(p+1) == long(p) + sizeof(T);

Чаще всего операции инкремента и декремента используются для

изменения переменных в цикле. Например, копирование строки,

оканчивающейся нулевым символом, задается следующим образом:

inline void cpy(char* p, const char* q)

{

while (*p++ = *q++) ;

}

Язык С++ (подобно С) имеет как сторонников, так и противников именно

из-за такого сжатого, использующего сложные выражения стиля

программирования. Оператор

while (*p++ = *q++) ;

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

Имеет смысл повнимательнее посмотреть на такие конструкции, поскольку

для C и C++ они не является редкостью.

Сначала рассмотрим более традиционный способ копирования массива

символов:

int length = strlen(q)

for (int i = 0; i<=length; i++) p[i] = q[i];

Это неэффективное решение: строка оканчивается нулем; единственный

способ найти ее длину - это прочитать ее всю до нулевого символа;

в результате строка читается и для установления ее длины, и для

копирования, то есть дважды. Поэтому попробуем такой вариант:

for (int i = 0; q[i] !=0 ; i++) p[i] = q[i];

p[i] = 0; // запись нулевого символа

Поскольку p и q - указатели, можно обойтись без переменной i,

используемой для индексации:

while (*q !=0) {

*p = *q;

p++; // указатель на следующий символ

q++; // указатель на следующий символ

}

*p = 0; // запись нулевого символа

Поскольку операция постфиксного инкремента позволяет сначала использовать

значение, а затем уже увеличить его, можно переписать цикл так:

while (*q != 0) {

*p++ = *q++;

}

*p = 0; // запись нулевого символа

Отметим, что результат выражения *p++ = *q++ равен *q. Следовательно,

можно переписать наш пример и так:

while ((*p++ = *q++) != 0) { }

В этом варианте учитывается, что *q равно нулю только тогда, когда

*q уже скопировано в *p, поэтому можно исключить завершающее

присваивание нулевого символа. Наконец, можно еще более сократить

запись этого примера, если учесть, что пустой блок не нужен, а

операция "!= 0" избыточна, т.к. результат условного выражения и так

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

первоначальному варианту, который вызывал недоумение:

while (*p++ = *q++) ;

Неужели этот вариант труднее понять, чем приведенные выше? Только

неопытным программистам на С++ или С! Будет ли последний вариант

наиболее эффективным по затратам времени и памяти? Если не считать

первого варианта с функцией strlen(), то это неочевидно. Какой из

вариантов окажется эффективнее, определяется как спецификой системы

команд, так и возможностями транслятора. Наиболее эффективный алгоритм

копирования для вашей машины можно найти в стандартной функции копирования

строк из файла <string.h>:

int strcpy(char*, const char*);

3.2.4 Поразрядные логические операции

Поразрядные логические операции

& | ^ ~ >> <<

применяются к целым, то есть к объектам типа char, short, int, long и

к их беззнаковым аналогам. Результат операции также будет целым.

Чаще всего поразрядные логические операции используются для

работы с небольшим по величине множеством данных (массивом разрядов).

В этом случае каждый разряд беззнакового целого представляет один

элемент множества, и число элементов определяется количеством разрядов.

Бинарная операция & интерпретируется как пересечение множеств,

операция | как объединение, а операция ^ как разность множеств.

С помощью перечисления можно задать имена элементам множества.

Ниже приведен пример, заимствованный из <iostream.h>:

class ios {

public:

enum io_state {

goodbit=0, eofbit=1, failbit=2, badbit=4

};

// ...

};

Состояние потока можно установить следующим присваиванием:

cout.state = ios::goodbit;

Уточнение именем ios необходимо, потому что определение io_state находится

в классе ios, а также чтобы не возникло коллизий, если пользователь заведет свои

имена наподобие goodbit.

Проверку на корректность потока и успешное окончание операции можно

задать так:

Характеристики

Тип файла
Документ
Размер
4,26 Mb
Тип материала
Учебное заведение
Неизвестно

Список файлов книги

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6510
Авторов
на СтудИзбе
302
Средний доход
с одного платного файла
Обучение Подробнее