Опубликован: 10.10.2006 | Уровень: специалист | Доступ: свободно
Лекция 3:

Выражения и операторы

3.2 Сводка операций

Здесь приводится краткая сводка операций и несколько примеров. Каждая операция сопровождается одним или несколькими характерными для нее именами и примером ее использования. В этих примерах class_name обозначает имя класса, member - имя члена, object - выражение, задающее объект класса, pointer - выражение, задающее указатель, expr - просто выражение, а lvalue (адрес) - выражение, обозначающее не являющийся константой объект. Обозначение (type) задает имя типа в общем виде (с возможным добавлением *, () и т.д.). Если оно указано без скобок, существуют ограничения.

Порядок применения унарных операций и операций присваивания "справа налево", а всех остальных операций - "слева направо". То есть, a=b=c означает a=(b=c), a+b+c означает (a+b)+c, и *p++ означает *(p++), а не (*p)++.

____________________________________________________________
   Операции С++
============================================================
::    Разрешение области видимости   class_name :: member
::    Глобальное  :: name
____________________________________________________________
.Выбор члена object . member
-> Выбор членаpointer -> member
[] Индексирование pointer [ expr ]
() Вызов функции expr ( expr_list )
() Структурное значениеtype ( expr_list )
sizeof   Размер объекта sizeof expr
sizeof   Размер типа sizeof ( type )
____________________________________________________________
++ Постфиксный инкремент  lvalue ++
++ Префиксный инкремент++ lvalue
-- Постфиксный декремент  lvalue --
-- Префиксный декремент-- lvalue
~Дополнение  ~ expr
!Логическое НЕ ! expr
-Унарный минус - expr
+Унарный плюс+ expr
&Взятие адреса & lvalue
*Косвенность * expr
newСоздание (размещение)  new type
delete   Уничтожение (освобождение)     delete pointer
delete[] Уничтожение массива delete[] pointer
() Приведение(преобразование)типа ( type ) expr
____________________________________________________________
. *Выбор члена косвенный  object . pointer-to-member
->*Выбор члена косвенный  pointer -> pointer-to-member
____________________________________________________________
*Умножениеexpr * expr
/Деление  expr / expr
%Остаток  от деления expr % expr
____________________________________________________________
+Сложение (плюс)     expr + expr
-Вычитание (минус)   expr - expr
____________________________________________________________

Все операции таблицы, находящиеся между двумя ближайшими друг к другу горизонтальными чертами, имеют одинаковый приоритет. Приоритет операций уменьшается при движении "сверху вниз". Например, a+b*c означает a+(b*c), так как * имеет приоритет выше, чем +; а выражение a+b-c означает (a+b)-c, поскольку + и - имеют одинаковый приоритет, и операции + и - применяются "слева направо".

____________________________________________________________
 Операции  С++ (продолжение)
============================================================
<< Сдвиг влево  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)   // ошибка: присваивание константы в условии
 // ...

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

Равиль Ярупов
Равиль Ярупов
Привет !
Федор Антонов
Федор Антонов
Оплата и обучение
Роман Островский
Роман Островский
Украина
Оксана Пагина
Оксана Пагина
Россия, Москва