Урок 38. Приоритет операций. Ассоциативность

   ⁄ 

 Обновлено 17 Апр 2017

  ⁄   

Чтобы правильно вычислять выражения (например, 4 + 2 * 3), мы должны знать, какие операторы что значат и в каком порядке их следует применять. Эта последовательность, в которой они выполняются, называется приоритетом операций. Следуя обычным правилам математики (в которой умножение следует выполнять перед сложением), выражение выше решается так — 4 + (2 * 3), результат — значение 10.

В C++ все операторы (операции) имеют свой уровень приоритета. Те, в которых он выше – выполняются первыми. В таблице ниже можно видеть, что приоритет операций умножения и деления (5) выше, чем в операциях сложения и вычитания (6). Компилятор использует это для определения порядка обработки выражений.

А что делать, если у двух операторов в выражении одинаковый уровень приоритета и они размещены рядом? Какую операцию выполнять первой? А здесь уже компилятор будет пользоваться правилами ассоциативности, которые указывают направление выполнения операций: слева направо или справа налево. Например, в 3 * 4 / 2, операции умножения и деления имеют одинаковый уровень приоритета — 5. А ассоциативность 5 уровня — слева направо, так что решать будем так: (3 * 4) / 2 = 6.

Таблица приоритета операций

Примечания:

 1 – это самый высокий уровень приоритета, а 17 – самый низкий. Операции с более высоким уровнем приоритета выполняются первыми.

 L -> R означает слева направо.

 R -> L означает справа налево.

Ассоциативность Оператор Описание Пример
1. Нет :: Глобальная область видимости (унарный) ::name
:: Область видимости класса (бинарный) class_name::member_name
2. L->R () Круглые скобки (expression)
() Вызов функции function_name(parameters)
() Инициализация type name(expression)
{} Uniform инициализация (C++11) type name{expression}
type() Functional cast new_type(expression)
type{} Functional cast (C++11) new_type{expression}
[] Индекс массива pointer[expression]
. Доступ к члену объекта object.member_name
-> Доступ к члену объекта через указатель object_pointer->member_name
++ Пост-инкремент lvalue++
–– Пост-декремент lvalue––
typeid Информация о типе во время выполнения typeid(type) or typeid(expression)
const_cast Cast away const const_cast(expression)
dynamic_cast Run-time type-checked cast dynamic_cast(expression)
reinterpret_cast Cast one type to another reinterpret_cast(expression)
static_cast Compile-time type-checked cast static_cast(expression)
3. R->L + Унарный плюс +expression
Унарный минус -expression
++ Пре-инкремент ++lvalue
–– Пре-декремент ––lvalue
! Логическое НЕ (NOT) !expression
~ Побитовое НЕ (NOT) ~expression
(type) C-style cast (new_type)expression
sizeof Размер в байтах sizeof(type) or sizeof(expression)
& Адрес &lvalue
* Dereference *expression
new Динамическое выделение памяти new type
new[] Динамическое распределение массива new type[expression]
delete Динамическое удаление памяти delete pointer
delete[] Динамическое удаление массива delete[] pointer
4. L->R ->* Member pointer selector object_pointer->*pointer_to_member
.* Member object selector object.*pointer_to_member
5. L->R * Умножение expression * expression
/ Деление expression / expression
% Остаток expression % expression
6. L->R + Сложение expression + expression
Вычитание expression — expression
7. L->R << Побитовый сдвиг влево expression << expression
>> Побитовый сдвиг вправо expression >> expression
8. L->R < Сравнение. Меньше чем expression < expression
<= Сравнение. Меньше чем или равно expression <= expression
> Сравнение. Больше чем expression > expression
>= Сравнение. Больше чем или равно expression >= expression
9. L->R == Равно expression == expression
!= Не равно expression != expression
10. L->R & Побитовое И (AND) expression & expression
11. L->R ^ Побитовое исключающее ИЛИ (XOR) expression ^ expression
12. L->R | Побитовое ИЛИ (OR) expression | expression
13. L->R && Логическое И (AND) expression && expression
14. L->R || Логическое ИЛИ (OR) expression || expression
15. R->L ?: Тернарный условный оператор (см. примечание ниже) expression ? expression : expression
= Присваивание lvalue = expression
*= Умножение с присваиванием lvalue *= expression
/= Деление с присваиванием lvalue /= expression
%= Деление с остатком с присваиванием lvalue %= expression
+= Сложение с присваиванием lvalue += expression
-= Вычитание с присваиванием lvalue -= expression
<<= Присваивание с побитовым сдвигом влево lvalue <<= expression
>>= Присваивание с побитовым сдвигом вправо lvalue >>= expression
&= Присваивание с побитовой операцией И (AND) lvalue &= expression
|= Присваивание с побитовой операцией ИЛИ (OR) lvalue |= expression
^= Присваивание с побитовой операцией «исключающее ИЛИ» (XOR) lvalue ^= expression
16. R->L throw Создание исключения вручную throw expression
17. L->R , Оператор Comma (запятая) expression, expression

Примечание: Выражение в середине условного оператора ?: выполняется как если бы оно находилось в круглых скобках.

Некоторые операторы вы уже знаете: +, -, *, /, (), =, <,>, <= и >=. Их значения одинаковы как в математике, так и в C++.

Однако, если у вас нет опыта работы с другими языками программирования, то большинство этих операторов вам сейчас непонятны. Это нормально. Мы рассмотрим большую часть из них в этой главе, а об остальных расскажем по мере необходимости.

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

Как возводить в степень в C++?

Вы уже должны были заметить, что оператор ^, который обычно используется для обозначения возведения в степень в обычной математике, не является таковым в C++. В С++ это побитовая операция XOR. Так что же тогда вместо ^? А вместо этого – функция pow(), которая находится в заголовочном файле <cmath>:

Обратите внимание, параметры и возвращаемые значения функции pow() — типа double. А поскольку типы с плавающей точкой известны ошибками округления, то результаты pow() могут быть слегка неточными (чуть меньше или чуть больше).

Если вам нужно возвести в степень целое число, то лучше использовать собственную функцию, например:

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

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

Тест

1) Из школьной математики вы знаете, что выражения внутри скобок выполняются первыми. Например, в (2 + 3) * 4, часть (2 + 3) будет выполнятся первой.

В этом задании есть 4 выражения, в которых отсутствуют какие-либо скобки. Используя приоритет операций и правила ассоциативности в таблице выше, добавьте скобки в каждое выражение так, как если бы их обрабатывал компилятор.

Подсказка: Используйте колонку Пример в таблице выше, чтобы определить, является ли оператор унарным (имеет один операнд) или бинарным (два операнда). Если забыли, что такое унарный или бинарный — смотрите урок 17.

Пример решения: х = 2 + 3 % 4

Бинарный оператор % имеет более высокий приоритет, чем оператор + или =, поэтому он применяется первым: х = 2 + (3 % 4);

Бинарный оператор + имеет более высокий приоритет, чем =, поэтому следующим применяется он.

Ответ: х = (2 + (3 % 4)).

Дальше нам уже не нужна таблица, чтобы понять, как будет вычисляться это выражение.

Задания

а) x = 3 + 4 + 5;
б) x = y = z;
в) z *= ++y + 5;
г) a || b && c || d;

Ответ

а) Уровень приоритета бинарного оператора + выше, чем в =:

х = (3 + 4 + 5);

Ассоциативность бинарного оператора + слева направо:

Ответ: х = ((3 + 4) + 5).

б) Ассоциативность бинарного оператора = справа налево:

Ответ: x = (y = z).

в) Унарный оператор ++ имеет наивысший приоритет:

z *= (++y) + 5;

Бинарный оператор + имеет второй наивысший приоритет:

Ответ:  z *= ((++y) + 5).

г) Бинарный оператор && имеет более высокий приоритет, чем ||:

a || (b && c) || d;

Ассоциативность бинарного оператора || слева направо:

Ответ: (a || (b && c)) || d.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (14 оценок, среднее: 5,00 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *