Будет ли i = i ++ четко определено в C17?

После того, как наткнулся на вопрос «Почему эти конструкции используют неопределенное поведение до и после инкремента?» сегодня Я решил взять последний черновик следующего стандарта C, который смог найти, и прочитать о нем больше.
Вскоре после того, как я обнаружил следующий абзац в черновике C17:

Выражение - это последовательность операторов и операндов, которая определяет вычисление значения или обозначает объект или функцию, или генерирует побочные эффекты, или выполняет их комбинацию. Вычисления значений операндов оператора последовательно выполняются перед вычислением значения результата оператора
Источник: ISO / IEC 9899: 2017, раздел 6.5 §1« Выражения » (ссылка не работает, используйте web. archive.org)

Теперь я немного запутался. Разве это не означает, что i = i++ - это определенное поведение? Я посмотрел на другой черновик, на этот раз C99:

Выражение - это последовательность операторов и операндов, которая определяет вычисление значения или обозначает объект или функцию, или генерирует побочные эффекты, или выполняет их комбинацию.
Источник: ISO / IEC 9899: 1999, раздел 6.5 §1 «Выражения»

Отсутствует это самое предложение!

Вопросов

  1. Я что-то неправильно понял?
  2. Ответы устарели?
  3. Я посмотрел не на тот черновик?

Примечание. этот вопрос связан с тем, что касается C ++.


person asynts    schedule 25.11.2018    source источник
comment
@asynts: C ++ - это совсем другой язык. Идентичный синтаксис / грамматика не подразумевает идентичную семантику.   -  person too honest for this site    schedule 25.11.2018
comment
Вы вообще читали версию стандарта C11? Это точно такой же текст. VtC как хорошо известный обман.   -  person too honest for this site    schedule 25.11.2018
comment
@toohonestforthissite ОП, похоже, хорошо об этом знает. Вопрос здесь в основном в том, соответствует ли C17 C ++ 17, например, C11 соответствует C ++ 11.   -  person Lundin    schedule 26.11.2018
comment
Повторное открытие, поскольку вопрос признает, что это UB в старых стандартах (и связан с данным дублированием), но спрашивает о новейшем стандарте.   -  person dbush    schedule 26.11.2018
comment
@dbush: существует только один стандарт, и вопрос заключается в том, изменилась ли формулировка, чего, по-видимому, не было . Другими словами: OP спрашивает, почему что-то изменилось, но не изменилось, и позволяет другим проводить сравнение.   -  person too honest for this site    schedule 29.11.2018
comment
@asynts: Стандартные версии C, начиная со второй, имеют предисловие, в котором отменяется предыдущая версия и перечислены важные изменения. В общем, когда речь идет о документе, его следует хорошо изучить, по крайней мере, видимые части. В любом случае, вы получили ответ на вопрос, так что я уйду отсюда.   -  person too honest for this site    schedule 30.11.2018


Ответы (2)


Выделенный вами отрывок говорит только о том, что выражения i++ и i оцениваются перед вычислением полного выражения i = i++. Это все еще неопределенное поведение, потому что i изменяется более одного раза в выражении без точки последовательности.

Этот отрывок впервые появился в C11, так что там без изменений по сравнению с версией C17.

person dbush    schedule 25.11.2018
comment
Значит, прирост не привязан к оценке? - person asynts; 25.11.2018
comment
@asynts Правильно. Любые побочные эффекты с правой стороны не связаны с назначением. - person dbush; 25.11.2018

Полная история. В C99 у нас был этот текст для 6.5.16 оператора присваивания:

Побочный эффект обновления сохраненного значения левого операнда должен возникать между предыдущей и следующей точкой последовательности.

Порядок оценки операндов не указан. Если предпринята попытка изменить результат оператора присваивания или получить к нему доступ после следующей точки последовательности, поведение не определено.

В C11 это было изменено на:

Побочный эффект обновления сохраненного значения левого операнда происходит после вычислений значений левого и правого операндов. Вычисления операндов не упорядочены.

Это просто другая (и того хуже) формулировка, две версии ведут себя одинаково - ключ является последним предложением в части C11, которая по-прежнему делает это неопределенным поведением, поскольку оценка левого операнда все еще не упорядочена по отношению к правому операнду. Вычисление значения относится только к отдельным операндам.

Текст C17 идентичен тексту C11. Итак, ответ: нет, i = i++; все еще является неопределенным поведением в C17.


Просто для справки сравните это с C ++ 11 (5.17):

Во всех случаях присваивание выполняется после вычисления значения правого и левого операндов и перед вычислением значения выражения присваивания.

Это примерно тот же текст, что и в C11, без явного указания «вычисления операндов неупорядочены». Это был недостаток C ++ 11, неясно, сделает ли это определенные выражения четко определенными или нет.

С ++ 17 дает пояснение (8.5.18):

Во всех случаях присваивание выполняется после вычисления значения правого и левого операндов и перед вычислением значения выражения присваивания. Правый операнд ставится перед левым операндом.

Итак, в C ++ 17 i=i++; определенно четко определен. И, как мы видим, формулировка является явной, в отличие от «без последовательности» в C11 / C17.

person Lundin    schedule 26.11.2018
comment
В присваивании x=y; я не думаю, что левый операнд вообще оценивается. В более сложном случае, таком как arr[i++]=y;, некоторые подвыражения в левом операторе будут вычисляться [неупорядоченным образом по отношению к правому операнду =], но выражение lvalue в целом не будет оценивается вообще. Я не думаю, что утверждение о том, что вычисления операндов неупорядочены, имеет отношение к операнду, который не оценивается. - person supercat; 27.11.2018
comment
@supercat ... если x не является изменчивым и не является регистром аппаратного флага для некоторого периферийного устройства MCU, чтение которого может вызвать изменение флагов. Тогда даже reg = reg & mask; будет иметь плохо определенное поведение (в отличие от эквивалента присваивания compount, но это уже другая история). Аналогично есть a[func()] = b[func()];, где func может иметь static переменных и так далее. - person Lundin; 27.11.2018
comment
Я хочу сказать, что отсутствие последовательности между операндами = само по себе не приведет к тому, что i=i++; вызовет UB, если все побочные эффекты, связанные с оценкой правой части, будут упорядочены до фактического присвоения. Напротив, поведение будет неопределенным для a[i]=i++;, a[i++]=i; или i+=i++;, так как во всех трех из этих случаев в левой части есть другие операции, которые предшествуют назначению. - person supercat; 27.11.2018
comment
Что касается сценария, в котором цель является изменчивой, существуют платформы с инструкциями чтения-изменения-записи, где инструкция, эквивалентная foo|=1;, будет иметь семантику, которая отличается от последовательности temp = foo; temp |= 1; foo = temp;, и я ожидал бы, что качественные реализации для таких платформ должны расширить свободу Предлагаемые аспектами volatile, определяемыми реализацией, для выбора одного из двух вариантов поведения в зависимости от того, как написано выражение, даже несмотря на то, что Стандарт не предусматривает случаев, когда формы не будут эквивалентны при простом левом операнде. - person supercat; 27.11.2018
comment
Кстати, я думаю, что стандарт C мог бы быть более ясным, если бы он ввел термин для адресации lvalue, чтобы означать идентификацию объекта, идентифицированного им - действие, которое было бы первым шагом оценки lvalue, присвоения ему или принятия его адрес Это проясняет, что делается с левым операндом a[i++]=j; .. - person supercat; 27.11.2018