Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
PYaVU_s.doc
Скачиваний:
44
Добавлен:
24.02.2016
Размер:
665.09 Кб
Скачать
    1. Старшинство и порядок выполнения

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

Операция

Вид операции

Порядок выполнения

()[].->

Выражение

Слева направо

-~!* &++--sizeof

Унарный

Справа налево

*/%

Мультипликативный

Слева направо

+-

Аддитивный

Слева направо

<< >>

Сдвиг

Слева направо

<> <= >=

Отношение (неравенство)

Слева направо

== !=

Отношение (равенство)

Слева направо

&

Побитовое И

Слева направо

^

Побитовое исключающее ИЛИ

Слева направо

|

Побитовое включающее ИЛИ

Слева направо

&&

Логическое И

Слева направо

||

Логическе ИЛИ

Слева направо

?:

Условная

Справа налево

= *= /= %=+= -= <<= >>=&= |= ^=

Простое и составное присваивание

Справа налево

,

Последовательное преобразование

Слева направо

Таблица 5‑12 Старшинство и порядок выполнения операций в Си

Из Таблица 5-12 следует, что операнды, состоящие из константы, идентификатора, строки, вызова функций, индексного выражения, выражения выбора элементов или скобочного выражения имеют высший приоритет и выполняются слево направо. Преобразование type-cast имеет то же самое старшинство и порядок выполнения как и унарные операторы. Выражения могут содержать различные операции одного старшинства. Когда несколько операций одного и того же уровня старшинства появляется в выражении, то они отрабатываются в соответствии с порядком их выполнения либо справа налево либо слева направо. Результат вычисления выражения, включающего несколько операций одного и того же старшинства, не зависит от порядка вычисления для операций умножения, сложения и побитовых операций. Компилятор может вычислять такие выражения в любом порядке, даже в случае, когда в выражении появляются скобки, специфицирующие порядок вычисления.

Важно: Только операция последовтельного вычисления (,) и логические операции И (&&) и ИЛИ (||) обеспечивают определенный порядок вычисления операндов. Операция последовательного вычисления (,) обеспечивает преобразование своих операндов слева направо. (Заметим, что запятая, разделяющая аргументы в вызове функции, не является операцией последовательного вычисления и не обеспечивает таких гарантий.)

Логические операции также обеспечивают вычисление своих операндов слева направо. Однако логические операции вычисляют минимальное число операндов, необходимое для определения результата выражения. Таким образом, некоторые операнды выражения могут быть не вычислены. Например, в выражении x && y ++ второй операнд y ++ вычисляется только тогда, когда x есть true (не нуль). Так что y не инкрементируется, когда x есть false (нуль).

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

Выражение

Группирование по умолчанию

a & b || c

(a & b) || c

a = b || c

a = (b || c)

q && r || s--

(q && r) || s--

В первом примере побитовая операция И (&) имеет большее старшинство, чем логическая операци ИЛИ (||), поэтому выражение a & b является первым операндом логической операции ИЛИ.

Во втором примере логическая операция ИЛИ (||) имеет большее старшинство, чем операция простого присваивания, поэтому выражение b || c представляет правый операнд в присваивании. Заметим, что значение , присваиваемое a, есть нуль или единица.

В третьем примере показано корректно оформленное выражение, которое может выработать неожиданный результат. Логическая операция И (&&) имеет более высокое старшинство, чем логическая операция ИЛИ (||), поэтому запись q && r группируется в операнд. Так как логические операции обеспечивают вычисление операндов слева направо, то выражение q && r вычисляется раньше, чем s--. Однако, если q && r выработает ненулевое значение, то s-- не будет вычисляться и s не декрементируется. Чтобы корректно решить эту проблему, необходимо чтобы s-- появилось в качестве первого операнда выражения, либо декрементировано отдельной операцией.

В следующем примере показано неверное выражение, которое вырабатывает программную ошибку.

Неверное выражение

Группирование по умолчанию

p == 0 ? p += 1 : p += 2

(p == 0 ? p += 1 : p) += 2

В этом примере операция эквивалентности (==) имеет наибольшее старшинство, поэтому p == 0 группируется в качестве операнда. Тернарный оператор (?:) имеет следующее старшинство. Его первым операндом является выражение p ==0, вторым операндом является выражение p +=1. Однако, последним операндом тернарной операции будет рассмотрен p, а не p += 2, так как в данном случае p по старшинству операций связан более тесно с тернарной операцией, а не с сотавной операцией присваивания. В результате будет выработана синтаксическая ошибка, поскольку += 2 не имеет левого операнда (Lvalue-выражения).

Чтобы предупредить ошибки подобного рода и сделать программу более наглядной, рекомендуется использовать скобки. Предыдущий пример может быть корректно офрмлен следующим образом:

(p == 0) ? (p += 1) : (p += 2)