Последовательность точек в с
Точка последовательности в императивном программировании определяет любую точку выполнения компьютерной программы, при которой гарантируется, что все побочные эффекты предыдущих оценок будут выполнены, и никаких побочных эффектов от последующих оценок еще не было выполнено.
Что это значит? Может кто-нибудь объяснить это простыми словами?
4 ответа
Когда возникает точка последовательности, это в основном означает, что вы гарантированно завершили все предыдущие операции.
Изменение переменной дважды без промежуточной точки последовательности является одним из примеров неопределенного поведения.
Например, i = i++;
не определено, потому что между двумя изменениями нет i
,
В Википедии есть список точек последовательности в стандартах C и C++, хотя окончательный список всегда следует брать из стандарта ISO. Из приложения C99 C:
Ниже приведены точки последовательности, описанные в 5.1.2.3:
- Вызов функции после оценки аргументов (6.5.2.2).
- Конец первого операнда следующих операторов: логическое И && (6.5.13); логическое ИЛИ || (6.5.14); условный? (6.5.15); запятая, (6.5.17).
- Конец полного декларатора: деклараторы (6.7.5);
- Конец полного выражения: инициализатор (6.7.8); выражение в выражении выражения (6.8.3); управляющее выражение оператора выбора (если или переключатель) (6.8.4); управляющее выражение оператора while или do (6.8.5); каждое из выражений оператора for (6.8.5.3); выражение в операторе возврата (6.8.6.4).
- Непосредственно перед возвратом библиотечной функции (7.1.4).
- После действий, связанных с каждым отформатированным спецификатором преобразования функций ввода / вывода (7.19.6, 7.24.2).
- Непосредственно до и сразу после каждого вызова функции сравнения, а также между любым вызовом функции сравнения и любым движением объектов, переданных в качестве аргументов для этого вызова (7.20.5).
С11 изменила формулировку. Похоже, что вырвался троичный оператор и добавлены некоторые подробности:
Ниже приведены точки последовательности, описанные в 5.1.2.3:
- Между оценками обозначения функции и фактическими аргументами в вызове функции и фактическим вызовом. (6.5.2.2).
- Между оценками первого и второго операндов используются следующие операторы: логическое И && (6.5.13); логическое ИЛИ || (6.5.14); запятая, (6.5.17).
- Между оценками первого операнда условного оператора?: И любым вторым и третьим операндами (6.5.15).
- Конец полного декларатора: деклараторы (6.7.6);
- Между оценкой полного выражения и следующим полным выражением, которое будет оценено. Ниже приведены полные выражения: инициализатор (6.7.9); выражение в выражении выражения (6.8.3); управляющее выражение оператора выбора (если или переключатель) (6.8.4); управляющее выражение оператора while или do (6.8.5); каждое из выражений оператора for (6.8.5.3); выражение в операторе возврата (6.8.6.4).
- Непосредственно перед возвратом библиотечной функции (7.1.4).
- После действий, связанных с каждым отформатированным спецификатором преобразования функций ввода / вывода (7.21.6, 7.28.2).
- Непосредственно перед и сразу после каждого вызова функции сравнения, а также между любым вызовом функции сравнения и любым движением объектов, переданных в качестве аргументов для этого вызова (7.22.5).
В отношении точек последовательности важно отметить, что они не являются глобальными, а должны рассматриваться как набор локальных ограничений. Например, в заявлении
a = f1(x++) + f2(y++);
Существует точка последовательности между вычислением x ++ и вызовом f1, а другая точка последовательности между оценкой y ++ и вызовом f2. Однако нет никакой гарантии относительно того, будет ли x увеличен до или после вызова f2, и не будет ли y увеличен до или после вызова x. Если f1 меняет y или f2 меняет x, результаты будут неопределенными (было бы законно для сгенерированного кода компилятора, например, прочитать x и y, увеличить x, вызвать f1, проверить y с ранее прочитанным значением и - если это изменилось - неистово выискивать и уничтожать все видео и товары Барни; я не думаю, что какие-либо реальные компиляторы генерируют код, который бы на самом деле это делал, увы, но это было бы разрешено в соответствии со стандартом).
Расширяя ответ Паксдиабло на примере.
Принять заявление
x = i++ * ++j;
Есть три побочных эффекта: присвоение результата i * (j+1)
к х, добавив 1 к i, и добавив 1 к j. Порядок применения побочных эффектов не определен; Каждый из i и j может быть увеличен сразу после оценки, или они не могут быть увеличены до тех пор, пока оба не будут оценены, но до того, как x был назначен, или они не могут быть увеличены до тех пор, пока x не был назначен.
Точка последовательности - это точка, в которой были применены все побочные эффекты (все x, i и j обновлены), независимо от порядка их применения.
Это означает, что компилятор может выполнять неожиданные оптимизации, трюки и магию, но он должен достичь четко определенного состояния в этих так называемых точках последовательности.