Будет ли я = 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++.

Ответы

Ответ 1

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

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

Ответ 2

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

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

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

Это было изменено в C11 на:

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

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

C17 имеет такой же текст, как C11. Таким образом, ответ: нет, i = i++; все еще неопределенное поведение в C17.


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

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

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

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

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

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