|
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_cast<type>(expr) |
|
преобразование типа |
dynamic_cast<type>(expr) |
reinterpret_cast |
приведение типа |
reinterpret_cast<type> (expr) |
static_cast |
приведение типа |
static_cast<type>(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 |
Назад Вперед
|