Порядок вычисления
Порядок вычисления операндов любого оператора C, включая порядок вычисления аргументов функции в выражении вызова функции и порядок вычисления подвыражений в любом выражении, не определён (за исключением случаев, указанных ниже). Компилятор вычисляет их в любом порядке и может выбрать другой порядок, когда то же выражение вычисляется снова.
В C нет понятия вычисления слева направо или справа налево, что не следует путать с ассоциативностью операторов слева направо и справа налево: выражение f1() + f2() + f3() разбирается как (f1() + f2()) + f3() из-за ассоциативности оператора + слева направо, но вызов функции f3 может быть вычислен первым, последним или между f1() или f2() во время выполнения.
Определения
Вычисления
Компилятор выполняет два вида вычислений для каждого выражения или подвыражения (оба из которых являются необязательными):
- вычисление значения: вычисление значения, возвращаемого выражением. Это может включать определение тождества объекта (оценка lvalue) или чтение значения, ранее присвоенного объекту (оценка rvalue)
- побочный эффект: доступ (чтение или запись) к объекту, обозначенному volatile lvalue, изменение (запись) в объект, атомарная синхронизация(с C11), изменение файла, изменение среды с плавающей точкой (если поддерживается) или вызов функции, выполняющей любое из этих операций.
Если выражение не производит побочных эффектов и компилятор может определить, что значение не используется, выражение может не вычисляться.
Порядок
«sequenced-before» — это асимметричное, транзитивное, парное отношение между вычислениями в рамках одного потока (оно может распространяться на потоки, если участвуют атомарные типы и барьеры памяти).
- Если присутствует точка последовательности между подвыражениями E1 и E2, то вычисление значения и побочные эффекты E1 упорядочены «sequenced-before» любым вычислением значения и побочным эффектом E2
|
(с C11) |
Правила
&& (логическое И), || (логическое ИЛИ) и , (запятая).?:
if/switch/while/do и перед следующим полным выражением.
5) Существует точка последовательности в конце полного декларатора. 6) Существует точка последовательности непосредственно перед возвратом библиотечной функции. 7) Существует точка последовательности после действия, связанного с каждым спецификатором преобразования в форматированном вводе/выводе (в частности, это правильно для scanf записи различных полей в ту же переменную и для printf чтения и изменения или изменения той же переменной более одного раза с использованием %n 8) Есть точки последовательности до и сразу после каждого вызова функции сравнения, выполняемой библиотечными функциями qsort и bsearch, а также между любым вызовом функции сравнения и перемещением связанных объектов, выполняемым qsort.
|
(с C99) |
| 9) Вычисления значений (но не побочных эффектов) операндов любого оператора упорядочены перед вычислением значения результата оператора (но не его побочных эффектов). 10) Побочный эффект (изменение левого аргумента) оператора прямого присваивания и всех операторов сложного присваивания упорядочен после вычисления значения (но не побочных эффектов) как левого, так и правого аргумента. 11) Вычисление значения операторов пост-инкремента и пост-декремента упорядочено до его побочного эффекта. 12) Вызов функции, который не упорядочен перед или после другого вызова функции, неопределённо упорядочен (инструкции процессора, составляющие разные вызовы функций, не могут быть чередованы, даже если функции инлайнены). 13) В выражениях списков инициализации все вычисления неопределённо упорядочены. 14) По отношению к неопределённо упорядоченному вызову функции, операция операторов сложного присваивания и обе формы префикса и постфикса операторов инкремента и декремента — это отдельные вычисления. | (с C11) |
Неопределённое поведение
i = ++i + i++; // undefined behavior i = i++ + 1; // undefined behavior f(++i, ++i); // undefined behavior f(i = -1, i = -1); // undefined behavior
f(i, i++); // undefined behavior a[i] = i++; // undefined bevahior
См. также
Порядок приоритетов операторов, определяющий, как выражения строятся из их представления в исходном коде.
| C++ документация по Порядку вычисления |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/eval_order