Order of evaluation
Порядок вычисления операндов любого оператора C++, включая порядок вычисления аргументов функции в выражении вызова функции, и порядок вычисления подвыражений в любом выражении не определён (за исключением случаев, указанных ниже). Компилятор может вычислять их в любом порядке и может выбрать другой порядок при повторном вычислении того же выражения.
В языке C не существует концепции вычисления слева направо или справа налево, что не следует путать с левоассоциативностью и правоассоциативностью операторов: выражение f1 ( ) + f2 ( ) + f3 ( ) парсится как ( f1 ( ) + f2 ( ) ) + f3 ( ) благодаря левоассоциативности operator + , но вызов функции f3 ( ) может быть вычислен первым, последним или между f1 ( ) и f2 ( ) во время выполнения.
Содержание |
Определения
Оценки
Компилятор выполняет два вида вычислений для каждого выражения или подвыражения (оба из которых являются опциональными):
- вычисление значения : вычисление значения, возвращаемого выражением. Это может включать определение идентификатора объекта ( вычисление lvalue ) или чтение значения, ранее присвоенного объекту (вычисление rvalue).
-
побочный эффект
: доступ (чтение или запись) к объекту, обозначенному
volatilelvalue, модификация (запись) объекта , атомарная синхронизация (since C11) , изменение файла, изменение окружения с плавающей точкой (если поддерживается), или вызов функции, выполняющей любое из этих действий.
Если выражение не производит побочных эффектов и компилятор может определить, что значение не используется, выражение может не вычисляться .
Упорядочивание
Sequenced-before — это асимметричное, транзитивное, парное отношение между вычислениями в пределах одного потока (оно может распространяться на несколько потоков при использовании атомарных типов и барьеров памяти).
- Если между подвыражениями E1 и E2 присутствует точка следования , то все вычисления значений и побочные эффекты E1 упорядочены перед любыми вычислениями значений и побочными эффектами E2 .
|
(начиная с C11) |
Правила
&&
(логическое И),
||
(логическое ИЛИ), и
,
(запятая).
?:
|
5)
Точка следования находится в конце полного декларатора.
6)
Точка следования находится непосредственно перед возвратом из библиотечной функции.
7)
Точка следования находится после действия, связанного с каждым спецификатором преобразования в форматированном вводе-выводе (в частности, корректно, когда
scanf
записывает разные поля в одну и ту же переменную, и когда
printf
читает и модифицирует или модифицирует одну и ту же переменную более одного раза с использованием
%
n
)
|
(since C99) |
|
9)
Вычисления значений (но не побочные эффекты) операндов любого оператора упорядочены до вычисления значения результата оператора (но не его побочных эффектов).
10)
Побочный эффект (модификация левого аргумента) оператора прямого присваивания и всех составных операторов присваивания упорядочен после вычисления значений (но не побочных эффектов) как левого, так и правого аргументов.
11)
Вычисление значения операторов постинкремента и постдекремента упорядочено до их побочного эффекта.
12)
Вызов функции, который не упорядочен до или после другого вызова функции, является неопределенно упорядоченным (инструкции процессора, составляющие разные вызовы функций, не могут перемежаться, даже если функции встроены)
13)
В выражениях
списка инициализации
все вычисления являются неопределенно упорядоченными
14)
По отношению к неопределенно упорядоченному вызову функции операции составных операторов присваивания, а также префиксные и постфиксные формы операторов инкремента и декремента являются единичными вычислениями.
|
(since 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 behavior
Смотрите также
Приоритет операторов который определяет, как выражения строятся из их представления в исходном коде.
|
Документация C++
для
Порядка вычислений
|