Namespaces
Variants

Order of evaluation

From cppreference.net

Порядок вычисления операндов любого оператора C++, включая порядок вычисления аргументов функции в выражении вызова функции, и порядок вычисления подвыражений в любом выражении не определён (за исключением случаев, указанных ниже). Компилятор может вычислять их в любом порядке и может выбрать другой порядок при повторном вычислении того же выражения.

В языке C не существует концепции вычисления слева направо или справа налево, что не следует путать с левоассоциативностью и правоассоциативностью операторов: выражение f1 ( ) + f2 ( ) + f3 ( ) парсится как ( f1 ( ) + f2 ( ) ) + f3 ( ) благодаря левоассоциативности operator + , но вызов функции f3 ( ) может быть вычислен первым, последним или между f1 ( ) и f2 ( ) во время выполнения.

Содержание

Определения

Оценки

Компилятор выполняет два вида вычислений для каждого выражения или подвыражения (оба из которых являются опциональными):

  • вычисление значения  : вычисление значения, возвращаемого выражением. Это может включать определение идентификатора объекта ( вычисление lvalue ) или чтение значения, ранее присвоенного объекту (вычисление rvalue).
  • побочный эффект  : доступ (чтение или запись) к объекту, обозначенному volatile lvalue, модификация (запись) объекта , атомарная синхронизация (since C11) , изменение файла, изменение окружения с плавающей точкой (если поддерживается), или вызов функции, выполняющей любое из этих действий.

Если выражение не производит побочных эффектов и компилятор может определить, что значение не используется, выражение может не вычисляться .

Упорядочивание

Sequenced-before — это асимметричное, транзитивное, парное отношение между вычислениями в пределах одного потока (оно может распространяться на несколько потоков при использовании атомарных типов и барьеров памяти).

  • Если между подвыражениями E1 и E2 присутствует точка следования , то все вычисления значений и побочные эффекты E1 упорядочены перед любыми вычислениями значений и побочными эффектами E2 .
  • Если вычисление A упорядочено перед вычислением B, то вычисление A будет завершено до начала вычисления B.
  • Если A не упорядочено перед B и B упорядочено перед A, то вычисление B будет завершено до начала вычисления A.
  • Если A не упорядочено перед B и B не упорядочено перед A, то существуют две возможности:
    • вычисления A и B являются неупорядоченными: они могут выполняться в любом порядке и могут перекрываться (в пределах одного потока выполнения компилятор может чередовать инструкции процессора, составляющие A и B)
    • вычисления A и B являются неопределённо-упорядоченными: они могут выполняться в любом порядке, но не могут перекрываться: либо A будет завершено до B, либо B будет завершено до A. Порядок может быть противоположным при следующем вычислении того же выражения.
(начиная с C11)

Правила

1) Существует точка следования после вычисления всех аргументов функции и обозначения функции, и перед фактическим вызовом функции.
2) Существует точка следования после вычисления первого (левого) операнда и перед вычислением второго (правого) операнда следующих бинарных операторов: && (логическое И), || (логическое ИЛИ), и , (запятая).
3) Существует точка следования после вычисления первого (левого) операнда и перед вычислением второго или третьего операнда (в зависимости от того, какой вычисляется) условного оператора ?:
4) Точка следования имеется после вычисления полного выражения (выражения, не являющегося подвыражением: обычно это то, что заканчивается точкой с запятой или управляющей инструкцией операторов if / switch / while / do ) и перед следующим полным выражением.
5) Точка следования находится в конце полного декларатора.
6) Точка следования находится непосредственно перед возвратом из библиотечной функции.
7) Точка следования находится после действия, связанного с каждым спецификатором преобразования в форматированном вводе-выводе (в частности, корректно, когда scanf записывает разные поля в одну и ту же переменную, и когда printf читает и модифицирует или модифицирует одну и ту же переменную более одного раза с использованием % n )
8) Точки следования находятся до и непосредственно после каждого вызова функции сравнения, выполняемого библиотечными функциями qsort и bsearch , а также между любым вызовом функции сравнения и перемещением связанных объектов, выполняемым qsort
(since C99)
9) Вычисления значений (но не побочные эффекты) операндов любого оператора упорядочены до вычисления значения результата оператора (но не его побочных эффектов).
10) Побочный эффект (модификация левого аргумента) оператора прямого присваивания и всех составных операторов присваивания упорядочен после вычисления значений (но не побочных эффектов) как левого, так и правого аргументов.
11) Вычисление значения операторов постинкремента и постдекремента упорядочено до их побочного эффекта.
12) Вызов функции, который не упорядочен до или после другого вызова функции, является неопределенно упорядоченным (инструкции процессора, составляющие разные вызовы функций, не могут перемежаться, даже если функции встроены)
13) В выражениях списка инициализации все вычисления являются неопределенно упорядоченными
14) По отношению к неопределенно упорядоченному вызову функции операции составных операторов присваивания, а также префиксные и постфиксные формы операторов инкремента и декремента являются единичными вычислениями.
(since C11)

Неопределённое поведение

1) Если побочный эффект на скалярном объекте не упорядочен относительно другого побочного эффекта на том же скалярном объекте, то поведение не определено .
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
2) Если побочный эффект на скалярном объекте неупорядочен относительно вычисления значения с использованием того же скалярного объекта, поведение не определено.
f(i, i++); // undefined behavior
a[i] = i++; // undefined behavior
3) Вышеуказанные правила применяются до тех пор, пока хотя бы один допустимый порядок вычисления подвыражений допускает такой неупорядоченный побочный эффект.

Смотрите также

Приоритет операторов который определяет, как выражения строятся из их представления в исходном коде.

Документация C++ для Порядка вычислений