Является ли int a = ++ i + ++ i неопределенным поведением? - PullRequest
2 голосов
/ 17 апреля 2020

Рассмотрим следующий код:

int main(){
  int i = 0;
  int a = ++i + ++i;
}

Я не могу найти информацию, которая говорит о том, что операнды + не секвенированы. Таким образом, в соответствии со стандартом, последовательность операндов двоичного кода + является неопределенно упорядоченной.

[intro, excution] / 15

Учитывая любые два оценки A и B, если A чередуется перед B (или, что то же самое, B чередуется после A), то выполнение A должно предшествовать выполнению B. Если A не чередуется до B, а B не чередуется до A, тогда A и B не секвенированы. [Примечание: выполнение непоследовательных оценок может частично совпадать. - примечание к концу]

Оценки A и B имеют неопределенную последовательность , когда последовательность A последовательно перед B или B последовательно перед A, но не определена, какая. [Примечание: неопределенные последовательности не могут перекрываются, но любой из них может быть выполнен первым. - примечание к концу]

Цитата означает, что оценка A может произойти до B, или оценка B может произойти до A. И выполнение непоследовательных оценок может перекрываться , тогда как неопределенно упорядоченные вычисления не могут перекрываться , которые отличаются.

Мы знаем, что модификация i всегда происходит до вычисления значения i из-за префикса ++.

Затем в соответствии с правилами:

Оценка выражения (или подвыражения) в целом включает оба вычисления значения (включая определение идентификатора объекта для оценки glvalue) и извлечение значения, ранее назначенного объекту для оценки значения) и инициирование побочных эффектов

Если побочный эффект в ячейке памяти не секвенирован относительно любого другого побочного эффекта в той же памяти местоположение или вычисление значения с использованием значения любого объекта в той же ячейке памяти, и т они не являются потенциально одновременными, поведение не определено

Так что независимо от того, является ли оценка A до B или наоборот, не существует побочных эффектов, связанных с вычислением соответствующего значения или побочный эффект для ++i + ++i;. Поскольку неопределенно упорядоченные оценки не могут перекрываться, одна из двух оценок должна быть полностью выполнена перед другой. Оценка включает в себя как расчет стоимости, так и побочный эффект. Следовательно, одно приращение до i оценивается раньше другого.

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

Обновление

Я нашел следующее предложение, которое, по-видимому, предполагает, что оценки не являются последовательными:

За исключением случаев, где указано, оценки операндов отдельных операторов и подвыражения отдельных выражений не секвенированы .

Однако я не знаю, как правильно понять предложение. Я придумал две интерпретации:

Для оператора A вычисления операндов A не последовательны друг с другом; для выражения B вычисления подвыражений B не связаны друг с другом.

и

Принимать оценки операндов отдельных операторов как A. Принимать оценки подвыражения отдельных выражений в виде B. A не секвенируется с B.

Какая интерпретация верна?

Ответы [ 2 ]

3 голосов
/ 17 апреля 2020

Стандартный текст 1 означает, что поведение не определено.

  • в <a>+<b> оценки <a> и <b> не последовательны 2,3
  • две части имеют побочный эффект, который влияет на одну и ту же область памяти

(1) Эта часть, на мой взгляд, однозначна и понятна, но я не уверен, что нет других частей, которые говорят об обратном или что какое-то понятие более высокого уровня (например, что такое выполнение программы) не является логически нарушенным из-за противоречивых правил. Учитывая сложность C ++, я на самом деле был бы весьма удивлен отсутствием ошибок.

(2) В случае перегруженного operator+ они были бы неопределенно упорядочены (так как правила те же, что и для функции вызов, таким образом НЕ неопределенное поведение: 8.5.1.2 [5] из N4713 говорит: «Постфиксное выражение секвенируется перед каждым выражением в списке выражений и любым аргументом по умолчанию. Инициализация параметра, включая вычисление каждого связанного значения и побочный эффект , является неопределенно упорядоченным по отношению к любому другому параметру "), но для нативных int s это не применяется, и поведение не определено.

(3) В тексте написано" За исключением отмеченных случаев, оценки операнды отдельных операторов и подвыражений отдельных выражений не являются последовательными ". Конечно, для унарных операторов этот вопрос не имеет значения (нет порядка для разговора), а для троичного оператора ?: существуют специальные правила последовательности. Часть о «подвыражениях» должна охватывать такие случаи, как a[++i][++i], где a, например, char **: в этом случае два идентичных подвыражения ++i не секвенированы и с побочными эффектами, изменяющими одно и то же место в памяти и таким образом неопределенное поведение. Я думаю, что абзац на самом деле более сложный, чем необходимый, потому что операнды оператора также являются подвыражениями выражения, поэтому последней части было достаточно.

1 голос
/ 20 апреля 2020

Позвольте мне дать ответы, чтобы сделать ответы на вопрос более ясными. Во-первых, рассмотрим следующее предложение

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

предложение может быть разделено на два

1. За исключением отмеченных случаев, оценки операндов отдельных операторов не являются последовательными.
2. За исключением отмеченных случаев, вычисления подвыражений отдельных выражений не являются последовательными.

Итак, что означает раздел 1? Это означает, что набор X состоит из этих операндов оператора, и каждый элемент набора X не секвенирован друг с другом, они не секвенированы .Предложение 2 аналогично предложению 1. Оно просто делает набор X состоящим из этих подвыражений выражения.

Эти операторы бинарного оператора + описаны в [expr.additive], и ​​в них ничего не сказано о последовательности операндов в этом разделе. Итак, правила 1 выполняются для оператора. Поэтому, как стандарт сказать, что непоследовательность может перекрываться, что это значит? Это означает, что «части каждой оценки могут даже чередоваться вместе» (@ Ben Voigt сказал в комментарии). Так что для ++i + ++i это обычно имеет место:

Если побочный эффект в области памяти не секвенирован относительно другого побочного эффекта в той же области памяти или вычисления значения с использованием значения любого объекта в той же области памяти, и они не являются потенциально одновременными поведение не определено

Итак, int a = ++i + ++i - неопределенное поведение, ключевой момент в этом вопросе состоит в том, чтобы понять следующее предложение:

За исключением отмеченных случаев, оценки операнды отдельных операторов и подвыражений отдельных выражений не являются последовательными.

...