Spec-Zone.ru › C

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

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

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

Определения

Вычисления

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

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

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

Порядок

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

  • Если присутствует точка последовательности между подвыражениями E1 и E2, то вычисление значения и побочные эффекты E1 упорядочены «sequenced-before» любым вычислением значения и побочным эффектом 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. (с C99)
9) Вычисления значений (но не побочных эффектов) операндов любого оператора упорядочены перед вычислением значения результата оператора (но не его побочных эффектов). 10) Побочный эффект (изменение левого аргумента) оператора прямого присваивания и всех операторов сложного присваивания упорядочен после вычисления значения (но не побочных эффектов) как левого, так и правого аргумента. 11) Вычисление значения операторов пост-инкремента и пост-декремента упорядочено до его побочного эффекта. 12) Вызов функции, который не упорядочен перед или после другого вызова функции, неопределённо упорядочен (инструкции процессора, составляющие разные вызовы функций, не могут быть чередованы, даже если функции инлайнены). 13) В выражениях списков инициализации все вычисления неопределённо упорядочены. 14) По отношению к неопределённо упорядоченному вызову функции, операция операторов сложного присваивания и обе формы префикса и постфикса операторов инкремента и декремента — это отдельные вычисления. (с 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 bevahior
3) Приведённые выше правила применяются, пока по крайней мере один допустимый порядок подвыражений допускает такой неупорядоченный побочный эффект.

См. также

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

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/eval_order

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API