С++ для начинающих

       

Приоритеты


Приоритеты операций задают последовательность вычислений в сложном выражении. Например, какое значение получит 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

преобразование типа

const_cast<type>(expr)

dynamic_cast

преобразование типа

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

выделение памяти

new (exprlist) 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


Содержание раздела