Что может быть подвыражением?

Я прочитал "C++. Primer plus. Stephen Prata" (6-е издание). На странице 209 было:

y = (4 + x++) + (6 + x++);

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

И я прочитал "Sequence Points and Expression Evaluation" Visual Systems Journal, август 2002 г. Клаус Крефт и Анжелика Лангер. Там было:

 x[i]=i++ + 1; 

Предположим, что переменная i имеет значение 1, прежде чем мы введем оператор. Что будет результатом вычисления этого выражения? Правильный ответ: мы не знаем. Однако программисты слишком часто полагают, что знают, что делает этот фрагмент программы. Типичные ответы включают: «x[1] будет иметь значение 2», или «x[2] будет иметь значение 2», или даже «x[1] будет иметь значение 3».

Третий вариант однозначно неверный. Этого не произойдет, потому что i++ является приращением постфикса и возвращает начальное значение i 1; следовательно, значение правой части присваивания равно 2, а не 3. [...] Пока все хорошо, но мы не знаем, какая запись массива x будет изменена. Будет ли индекс 1 или 2, когда значение правой части будет присвоено x[i]?

На этот вопрос нет однозначного ответа. Это полностью зависит от порядка, в котором компилятор оценивает подвыражения. Если компилятор начнет с правой стороны присваивания и вычислит i++ + 1 до того, как он определит, какой позиции в массиве нужно присвоить x, тогда x[2] будет изменено, поскольку i уже было увеличено в ходе вычисления подвыражения i++. И наоборот, если компилятор начинает с левой стороны и выясняет, что он должен присвоить позицию i в массиве x, которая в это время все еще будет позицией 1, прежде чем он вычислит правую часть, тогда мы получим модификация x[1]. Оба исхода равновероятны и одинаково правильны. "

Как понять, где находится подвыражение? 4 + x++ и 6 + x++ являются подвыражениями, потому что они заключены в круглые скобки? x[i] и i++ + 1 являются частью выражения? Почему? Меня это интересует, потому что я хочу понять, где в гипотезе может произойти побочный эффект.


person Anastasia_P    schedule 25.04.2016    source источник
comment
Вся посылка этого вопроса кажется сомнительной. Например. 1.9/15 ясно говорит, что вычисление значений операндов оператора выполняется до вычисления значения результата оператора. Очевидно, что для оценки a + b сначала нужно оценить a и b. Что не является последовательностями, так это a и b по отношению друг к другу. Или, что в вашем коде проблематично, так это два отдельных выражения x++ по отношению друг к другу. Поскольку ни один из них не упорядочен перед другим, программа имеет неопределенное поведение.   -  person Kerrek SB    schedule 26.04.2016
comment
@KerrekSB C++ 11 ‹-› точки следования.   -  person dyp    schedule 26.04.2016
comment
@dyp: я не уверен, что этот вопрос касается исторического, устаревшего стандарта; в любом случае, я не думаю, что 4 + x++ когда-либо был двусмысленным. x++ оценивается перед +. Проблема исходит от другого x++. Причины могли измениться, но я считаю, что это всегда было неопределенным поведением. Никогда не гарантировалось, что x будет увеличено дважды.   -  person Kerrek SB    schedule 26.04.2016
comment
@KerrekSB Я согласен, это также UB с моделью Sequence Point. Я просто думаю, что споры о статье 12-летней давности и, казалось бы, такой же старой книге не помогут, если использовать Стандарт с новой/пересмотренной моделью оценки.   -  person dyp    schedule 26.04.2016
comment
@dyp Книге Саида, по-видимому, всего пять лет, и она утверждает, что охватывает C ++ 11. Ну что ж.   -  person T.C.    schedule 26.04.2016
comment
@Т.С. Он не называется Primer plus без всякой причины ;) -- А если серьезно, какое отношение он имеет к C++ Primer?   -  person dyp    schedule 26.04.2016
comment
@dyp Очевидно, никакого отношения.   -  person T.C.    schedule 26.04.2016
comment
Единственное, что вы можете знать об этих фрагментах кода, это то, что программа, которая их выполняет, не является корректной программой на C++. Я бы не стал доверять ни одному из этих источников ни в чем.   -  person molbdnilo    schedule 26.04.2016
comment
Ясно, что они означают выражение, которое является частью другого выражения.   -  person M.M    schedule 26.04.2016
comment
Не часть вопроса, но однозначного ответа на этот вопрос нет. является ложным. Есть однозначный ответ: выражение вызывает неопределенное поведение   -  person M.M    schedule 26.04.2016


Ответы (2)


Что может быть подвыражением?

Любое выражение может быть подвыражением. Хотя некоторые выражения могут не быть подвыражениями некоторых других выражений.

4 + x++ и 6 + x++ являются подвыражениями

Верный. Оба они являются арифметическими выражениями, если быть точнее, дополнениями.

потому что они в круглых скобках?

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

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

x[i] и i++ + 1 являются частью выражения? Почему?

Да. См. .

Вот удобный список всех возможных выражений в C++.

Найдем подвыражения в y = (4 + x++) + (6 + x++);. Первое выражение, не имеющее подвыражений, это 4. Это буквально. Это подвыражение 4 + x++, которое является дополнением. Дополнения имеют вид A + B. В этом случае подвыражение A равно 4, а подвыражение B равно x++, что является постинкрементом. О, но это также содержит подвыражение: x. Это идентификатор и не содержит подвыражений. 4 + x++ является частью выражения в скобках (4 + x++). Это подвыражение (4 + x++) + (6 + x++), которое является подвыражением y = (4 + x++) + (6 + x++);, которое является присваиванием. Присваивание является полным выражением, а не подвыражением. Я оставил некоторые подвыражения неисследованными и оставлю их в качестве упражнения для читателя.

person eerorika    schedule 25.04.2016
comment
user2079303, большое спасибо за подробный ответ и ту ссылку. Информации о подвыражении не нашел, видимо, искал на российских сайтах. ;) Я очень рад, что здесь есть люди, готовые помочь. - person Anastasia_P; 26.04.2016
comment
Получается, что x++ назвал декремент-выражением или я ошибаюсь? - person Anastasia_P; 26.04.2016
comment
@Anastasia_P нет, это выражение приращения. Точнее, приращение поста. - person eerorika; 26.04.2016
comment
У вас есть ссылки о побочных эффектах? - person Anastasia_P; 26.04.2016

Разбивая это, линия

y = (4 + x++) + (6 + x++);

является выражением-оператором. Такая вещь состоит из выражения, за которым следует ;, поэтому

y = (4 + x++) + (6 + x++)

является выражением.

Поскольку это выражение является не частью другого выражения (а только выражения-оператора), оно является полным выражением< /эм>. С другой стороны, подвыражение — это выражение, которое является частью другого выражения. В дальнейшем я буду использовать заглавные буквы для обозначения выражений, а не идентификаторов C++.

Приведенное выше полное выражение представляет собой выражение-присваивания в форме:

y = A

где A - оставшееся аддитивное выражение

(4 + x++) + (6 + x++)

Аддитивное выражение имеет форму X + Y, поэтому мы разбиваем его на два выражения.

(4 + x++)
(6 + x++)

Первый состоит из выражения вида (Z), где Z равно 4 + x++. А 4 + x++ состоит из двух выражений 4 и x++. И так далее. Все эти выражения являются частью

y = (4 + x++) + (6 + x++)

и, следовательно, они являются подвыражениями приведенного выше выражения.

person dyp    schedule 25.04.2016