C++ для начинающих.

4.13. Приоритеты.

Приоритеты операций задают последовательность вычислений в сложном выражении. Например, какое значение получит ival?

Int ival = 6 + 3 * 4 / 2 + 2;

Если вычислять операции слева направо, получится 20. Среди других возможных результатов будут 9, 14 и 36. Правильный ответ: 14.

В С++ умножение и деление имеют более высокий приоритет, чем сложение, поэтому они будут вычислены раньше. Их собственные приоритеты равны, поэтому умножение и деление будут вычисляться слева направо. Таким образом, порядок вычисления данного выражения таков:

1. 3 * 4 = 12.

2. 12 / 2 = 6.

3. 6 + 6 = 12.

4. 12 + 2 = 14.

Следующая конструкция ведет себя не так, как можно было бы ожидать. Приоритет операции присваивания меньше, чем операции сравнения:

While ( ch = nextChar() != '\n' ).

Программист хотел присвоить переменной ch значение, а затем проверить, равно ли оно символу новой строки. Однако на самом деле выражение сначала сравнивает значение, полученное от nextChar(), с '\n', и результат – true или false – присваивает переменной ch.

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

4 * 5 + 7 * 2 == 34.

4 * ( 5 + 7 * 2 ) == 76.

4 * ( (5 + 7) * 2 ) == 96.

Вот как с помощью скобок исправить поведение предыдущего примера:

While ( (ch = nextChar()) != '\n' ).

Операторы обладают и приоритетом, и ассоциативностью. Оператор присваивания правоассоциативен, поэтому вычисляется справа налево:

Ival = jval = kva1 = lval.

Сначала kval получает значение lval, затем jval – значение результата этого присваивания, и в конце концов ival получает значение jval.

Арифметические операции, наоборот, левоассоциативны. Следовательно, в выражении.

Ival + jval + kva1 + 1va1.

Сначала складываются ival и jval, потом к результату прибавляется kval, а затем и lval.

В таблице 4.4 приведен полный список операторов С++ в порядке уменьшения их приоритета. Операторы внутри одной секции таблицы имеют равные приоритеты. Все операторы некоторой секции имеют более высокий приоритет, чем операторы из секций, следующих за ней. Так, операции умножения и деления имеют одинаковый приоритет, и он выше приоритета любой из операций сравнения.

Упражнение 4.18.

Каков порядок вычисления следующих выражений? При ответе используйте таблицу 4.4.

(a) ! ptr == ptr-next.

(b) ~ uc ^ 0377 ui 4.

(c) ch = buf[ bp++ ] != '\n'.

Упражнение 4.19.

Все три выражения из предыдущего упражнения вычисляются не в той последовательности, какую, по-видимому, хотел задать программист. Расставьте скобки так, чтобы реализовать его первоначальный замысел.

Упражнение 4.20.

Следующие выражения вызывают ошибку компиляции из-за неправильно понятого приоритета операций. Объясните, как их исправить, используя таблицу 4.4.

(a) int i = doSomething(), 0;

(b) cout ival % 2 ? "odd" : "even";

Таблица 4.4. Приоритеты операций.

Оператор. Значение. Использование.
:: Глобальная область видимости. ::name.
:: Область видимости класса. Class::name.
:: Область видимости пространства имен. Namespace::name.
. Доступ к члену. Object.member.
- Доступ к члену по указателю. Pointer-member.
[] Взятие индекса. Variable[expr].
() Вызов функции. Name(expr_list).
() Построение значения. Type(expr_list).
++ Постфиксный инкремент. Lvalue++
Постфиксный декремент. Lvalue--
Typeid. Идентификатор типа. Typeid(type).
Typeid. Идентификатор типа выражения. Typeid(expr).
Преобразование типа. Const_casttype(expr).
Преобразование типа. Dynamic_casttype(expr).
Reinterpret_cast. Приведение типа. Reinterpret_casttype (expr).
Static_cast. Приведение типа. Static_casttype(expr).
Sizeof. Размер объекта. Sizeof expr.
Sizeof. Размер типа. Sizeof( type).
++ Префиксный инкремент. ++lvalue.
-- Префиксный декремент. --lvalue.
~ Побитовое НЕ. ~expr.
! Логическое НЕ. !expr.
- Унарный минус. -expr.
+ Унарный плюс. +expr.
* Разыменование. *expr.
Адрес. Expr.
() Приведение типа. (type)expr.
New. Выделение памяти. New type.
New. Выделение памяти и инициализация. New type(exprlist).
New. Выделение памяти под массив. Все формы.
Delete. Освобождение памяти. Все формы.
Delete. Освобождение памяти из-под массива. Все формы.
-* Доступ к члену классу по указателю. Pointer- *pointer_to_member.
.* Доступ к члену класса по указателю. Object.*pointer_to_member.
* Умножение. 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 ^ expr.
| Побитовое ИЛИ. Expr | expr.
Логическое И. Expr expr.
|| Логическое ИЛИ. Expr || expr.
?: Условный оператор. Expr ? expr * expr.
= Присваивание. L-значение = expr.
=, *=, /=, %=, +=, -=, =, =, =, |=, ^= Составное присваивание. L-значение += expr и т.д.
Throw. Возбуждение исключения. Throw expr.
, Запятая. Expr, expr.