В тесте мне задали следующий вопрос (я не хотел писать его сам. Его задавал тест. Я все еще знаю его плохой код) об оценке ++ * ptr ++
int Ar[ ] = { 6 , 3 , 8 , 10 , 4 , 6 , 7} ;
int *Ptr = Ar ;
cout<<++*Ptr++ ;
Однако я подозреваю, что это неопределенное поведение, поскольку это может быть как (++*ptr)++, так и ++(*ptr++).
Это? Я плохо знаком с документацией, поэтому ничего не нашел.
Нет, это правильно.
Когда вы спрашиваете о «неопределенном поведении», лучше всего сначала заглянуть в документацию.
Зачем вообще писать такой код, независимо от его правильности?
@soham: Вообще говоря, вопрос о сложных взаимодействиях нескольких экземпляров ++ и тому подобном, который представляет собой код, который должен никогда не быть написанным, вызовет отрицательные голоса. Или, другими словами, если вам нужно спросить, четко ли он определен, не пишите так.
@tadman извини, но я не понял твою точку зрения
@soham Как ты думаешь, почему это не определено? Я думаю, вы получили бы меньше голосов против, если бы вы объяснили это в вопросе.
Комбинирование операторов префикса и постфиксного приращения жестоко по отношению к любому, кто пытается прочитать этот код и понять ваши намерения. Если вы подозреваете, что это неопределенное поведение, первым делом следует изучить спецификацию C++ или хороший справочник по операторам пре- и пост-инкремента и тому, как они могут работать с операцией разыменования указателя.
@MatteoItalia Это было задано в тесте, сэр ... Я не хотел писать это сам
Если вы действительно хотите это сделать, возможно, попробуйте переписать его как ++(*(ptr++)). Легче понять.
@soham Обычно такие уродливые выражения вызывают UB, если / когда они изменяют переменную более одного раза в одном месте. Поскольку этот нет (один ++ изменяет указатель, другой ++ изменяет указанный int), он четко определен.
@tadman на самом деле, если вы подозреваете, что он не определен, первый и единственный шаг - переписать выражение, устраняющее сомнения.
@soham правильный ответ на этот тест "человек, написавший это, должен быть уволен"
Вы должны были отметить вопрос как языковый юрист. Тогда комментарии типа «почему вы это сделали?» Были бы неприменимы, и вопрос был бы рассмотрен по существу.
Увольнения могут быть чрезмерными, но они, безусловно, получают неприятный запах во время проверки кода и уходят на переписывание перед второй проверкой кода. Если они провалили этот обзор по тем же причинам ...
Это просто; он же cout<<(*Ptr+++=1); ;-)
Я думаю, что это на самом деле хороший контрольный вопрос, потому что он проверяет, понимаете ли вы, что ++*ptr делает что-то отличное от *++ptr, и формулировка этого таким образом заставляет тестируемого задействовать свой мозг, а не повторять заученный факт.
В этом коде четко определено поведение разработчика, которого сильно бьет по голове тот, кто должен это поддерживать.
@zwol: OTOH, это плохой вопрос для тех, кто (как я) использует скобки для принудительного выполнения порядка оценки, а не зависит от моей памяти о правилах приоритета. Знаете, у меня так много мозговых клеток, и мне есть чем заняться с ними :-)
также может быть записан как ++Ptr++[0]
Вот почему каждый программист на C / C++ должен иметь свою таблицу приоритетов операторов под своей клавиатурой (en.wikipedia.org/wiki/…) ...
Я бы предпочел ++(++Ptr)[-1] или даже ++-1[++Ptr], потому что пре-инкремент всегда лучше пост-инкремента (этот комментарий может содержать сарказм).





However I suspect this is undefined behaviour since it can be both
(++*ptr)++or++(*ptr++). Is it?
Не совсем, в отличие от поведения во время выполнения, которое дает широкую свободу действий разработчикам, в C++ сам синтаксический анализ следует довольно строгим и четко определенным правилам 1. Действительно, если посмотреть на правила приоритета, ++*Ptr++ фактически анализируется как ++(*(Ptr++)).
Вместо этого этот вопрос с подвохом, вероятно, намекает на неопределенное поведение выражений, таких как i = ++i + ++i, где у вас есть значение, которое появляется несколько раз в выражении и подвергается модификации побочным эффектом самого выражения. Такие выражения являются недопустимыми, поскольку, если не существует какого-либо оператора, который устанавливает последовательность побочных эффектов 2, точный момент их применения не определен, поэтому не определено, какие именно значения i примет в различных точках выражения.
Тем не менее, здесь нет неопределенного поведения, поскольку все побочные эффекты в выражении работают с разными значениями, которые появляются в выражении только один раз: «внутренний» ++ влияет на Ptr, а внешний влияет на значение, указанное изначально Ptr, то есть Ar[0]. .
++(*(Ptr++))
^^^^^____increments Ptr, returning its original value
^^^^^^^^______dereferences the original Ptr, AKA &Ar[0]
^^^^^^^^^^^^_______ increments Ar[0]
При этом, если бы я когда-либо видел такое выражение в нашей кодовой базе, я бы пошел на все, чтобы найти автора и убедиться, что это больше не повторится.
@val что сделало это законным?
Поведение i = ++i + ++i не определено в C++ 17.
@val: только что проверил еще раз: это незаконно. C++ 17 просто добавил точку последовательности для операторов присваивания и составного присваивания. stackoverflow.com/a/46171943/214671++i + ++i остается незаконным даже сам по себе (без присваивания слева).
@MatteoItalia, более формально intro.execution, операнды оператора сложения неупорядочены
Также на cppreference; с пункта 14 - модификации, введенные в C++ 17; они что-то особенное (и значительно больше, чем ответ, который я привел выше), но они не включают добавление.
Что, если *Ptr ссылается на сам Ptr, приведет ли это к неопределенному поведению?
Re: «Такие выражения [как i = ++i + ++i] являются незаконными, поскольку, если не существует какого-либо оператора, который упорядочивает побочные эффекты, точный момент, в который они применяются, не определен, поэтому не определено, какие именно значения i примет в различных точках выражение ": Я не уверен, что согласен с этим объяснением. Это объяснение объяснило бы, почему поведение i = ++i + ++i было неопределенные, если бы это было так; но поведение полностью соответствует неопределенный, и это объяснение на самом деле не объясняет, почему.
@ruakh Не определено, потому что не может быть определено. В нем слишком много двусмысленности. Вопрос «Почему это не определено» возникает из-за того, что вы не можете его определить.
@ruakh: в конце концов, он не определен, потому что в стандарте указано, что он не определен; Хорошее обоснование состоит в том, что стандарт оставлял разработчикам так много возможностей для применения побочных эффектов всякий раз, когда и как бы они ни чувствовали себя лучше всего, что они прошли весь путь и оставили его полностью неопределенным, чтобы обеспечить любую возможную оптимизацию (скажем, сохранить половину значения в какой-то момент, а другая половина - позже, тем временем генерируя представление ловушки).
Этот
++*Ptr++;
не вызывает U.B и оценивается как ++(*(Ptr++))
ptr++;/* address post incremented i.e doesn't change here itself */*ptr;/* dereference same address i.e value at location where ptr earlier pointed i.e 6 */++*ptr;/* value changed where ptr pointed i.e Ar[0] becomes 7 */Обратите внимание, что приращения поста Ptr++ оцениваются как
Ptr;/* Ptr doesn't change here itself in same expression */Ptr = Ptr + 1;/* in next expression, Ptr considers the incremented one */
Что сделал с вами C++, что вы чувствуете себя обязанным это сделать?