Jump to content

Точка последовательности

В C и C++ точка последовательности определяет любую точку компьютерной программы , выполнения в которой гарантируется, что все побочные эффекты предыдущих вычислений будут выполнены, и никакие побочные эффекты последующих вычислений еще не были выполнены. Они являются основной концепцией для определения достоверности и, если допустимы, возможных результатов выражений. Добавление дополнительных точек последовательности иногда необходимо, чтобы определить выражение и обеспечить единый допустимый порядок вычислений.

В C11 и C++11 использование термина «точка последовательности» было заменено на «упорядочение». Есть три возможности: [1] [2] [3]

  1. Вычисление выражения может быть упорядочено перед вычислением другого выражения или, что эквивалентно, вычисление другого выражения может быть расположено после вычисления первого.
  2. Вычисление выражений имеет неопределенную последовательность, то есть одно упорядочивается перед другим, но какое именно значение не указано.
  3. Вычисление выражений не является последовательным.

Выполнение неупорядоченных оценок может перекрываться, что приводит к потенциально катастрофическому неопределенному поведению, если они имеют общее состояние . Такая ситуация может возникнуть при параллельных вычислениях , вызывая условия гонки , но неопределенное поведение также может привести к однопоточным ситуациям. Например, a[i] = i++; (где a представляет собой массив и i является целым числом) имеет неопределенное поведение.

Примеры двусмысленности [ править ]

Рассмотрим две функции f() и g(). В C и C++ + оператор не связан с точкой последовательности, поэтому в выражении f()+g() возможно, что либо f() или g() будет выполнен первым. Оператор запятая вводит точку последовательности, и поэтому в коде f(),g() определен порядок оценки: сначала f() называется, а затем g() называется.

Точки последовательности также вступают в игру, когда одна и та же переменная изменяется более одного раза в одном выражении. Часто цитируемым примером является C выражение i=i++, что, по-видимому, оба присваивает i его предыдущее значение и приращения i. Окончательное значение i неоднозначно, поскольку в зависимости от порядка вычисления выражения приращение может происходить до, после или чередоваться с присваиванием. Определение конкретного языка может указывать одно из возможных вариантов поведения или просто говорить, что поведение не определено . В C и C++ вычисление такого выражения приводит к неопределенному поведению. [4] Другие языки, такие как C# , определяют приоритет оператора присваивания и увеличения таким образом, что результат выражения i=i++ гарантировано.

Поведение [ править ]

До C++03 [ править ]

В С [5] и С++, [6] Точки последовательности встречаются в следующих местах. (В C++ перегруженные операторы действуют как функции, и поэтому перегруженные операторы вводят точки последовательности так же, как вызовы функций.)

  1. Между вычислением левого и правого операндов && ( логическое И ), || ( логическое ИЛИ ) (как часть сокращенной оценки ) и операторы-запятые . Например, в выражении *p++ != 0 && *q++ != 0, все побочные эффекты подвыражения *p++ != 0 завершаются до любой попытки доступа q.
  2. Между оценкой первого операнда тернарного условного оператора и его второго или третьего операнда. Например, в выражении a = (*p++) ? (*p++) : 0 после первого есть точка последовательности *p++, что означает, что оно уже было увеличено к моменту выполнения второго экземпляра.
  3. В конце полного выражения. В эту категорию входят операторы выражения (например, оператор присваивания a=b;), операторы возврата , управляющие выражения if, switch, while, или do- while утверждения, и каждое из трех выражений в for заявление.
  4. Прежде чем функция будет введена в вызов функции. Порядок, в котором оцениваются аргументы, не указан, но эта точка последовательности означает, что все их побочные эффекты завершаются до входа в функцию. В выражении f(i++) + g(j++) + h(k++), f вызывается с параметром исходного значения i, но i увеличивается перед входом в тело f. Сходным образом, j и k обновляются перед вводом g и h соответственно. Однако не уточняется, в каком порядке f(), g(), h() выполняются и в каком порядке i, j, k увеличиваются. Если тело f обращается к переменным j и k, он может обнаружить, что были увеличены оба значения, ни одно из них, или только одно из них. (вызов функции f(a,b,c) не используется оператор запятая; порядок оценки a, b, и c не указано.)
  5. При возврате функции, после того как возвращаемое значение копируется в вызывающий контекст. (Эта точка последовательности указана только в стандарте C++; в C она присутствует только неявно. [7] )
  6. В конце инициализатора ; например, после оценки 5 в декларации int a = 5;.
  7. Между каждым декларатором в каждой последовательности деклараторов; например, между двумя оценками a++ в int x = a++, y = a++. [8] (Это не пример оператора запятой.)
  8. После каждого преобразования связан спецификатор формата ввода/вывода. Например, в выражении printf("foo %n %d", &a, 42), после %n оценивается и перед печатью 42.

C11 и C++11 [ править ]

Частично из-за введения языковой поддержки потоков в C11 и C++11 введена новая терминология для порядка вычислений. Одна операция может быть «последовательной» перед другой, либо обе операции могут быть «неопределенно» упорядоченными (одна должна завершиться раньше другой) или «неупорядоченными» (операции в каждом выражении могут чередоваться).

С++17 [ править ]

В C++17 ограничены некоторые аспекты порядка вычислений. new выражение всегда будет выполнять выделение памяти перед оценкой аргументов конструктора. Операторы <<, >>, ., .*, ->*, а индекс и оператор вызова функции гарантированно будут оцениваться слева направо (независимо от того, перегружены они или нет). Например, код

std::cout << a() << b() << c();   // parsed as (((std::cout << a()) << b()) << c());

недавно гарантированно позвонит a, b и c в таком порядке. Правая часть любого оператора присваивания вычисляется раньше левой, так что b() *= a(); гарантированно оценит a первый. Наконец, хотя порядок вычисления параметров функции остается определяемым реализацией, компилятору больше не разрешено чередовать подвыражения для нескольких параметров. [9]

См. также [ править ]

Ссылки [ править ]

  1. ^ «ИСО/МЭК 14882:2011» . Проверено 4 июля 2012 г.
  2. ^ «Более детальная альтернатива точкам последовательности (пересмотренная) (WG21/N2239 J16/07-0099)» . Проверено 5 июля 2012 г.
  3. ^ «Порядок оценки» . Проверено 14 октября 2015 г.
  4. ^ Пункт 6.5#2 спецификации C99 : «Между предыдущей и следующей точкой последовательности сохраненное значение объекта должно быть изменено не более одного раза путем оценки выражения. Кроме того, доступ к предыдущему значению должен быть доступен только для определения значения для храниться».
  5. ^ В приложении C спецификации C99 перечислены обстоятельства, при которых можно предположить точку последовательности.
  6. ^ В стандарте C++ 1998 года точки последовательности для этого языка перечислены в разделе 1.9, параграфы 16–18.
  7. ^ Стандарт C++, ISO 14882:2003, раздел 1.9, сноска 11.
  8. ^ Стандарт C++, ISO 14882:2003, раздел 8.3: «Каждый init-декларатор в объявлении анализируется отдельно, как если бы он находился в объявлении сам по себе».
  9. ^ Дос Рейс, Габриэль; Саттер, Херб; Кейвс, Джонатан (23 июня 2016 г.). «Уточнение порядка оценки выражений для идиоматического C++» (PDF) . open-std.org . стр. 1–5 . Проверено 28 апреля 2023 г.

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 936385c08f2fdb6e06f99136a33b5546__1694693940
URL1:https://arc.ask3.ru/arc/aa/93/46/936385c08f2fdb6e06f99136a33b5546.html
Заголовок, (Title) документа по адресу, URL1:
Sequence point - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)