170 похожих чатов

Здесь выше рассматривался пример, насчет которого как минимум у GCC

и CLang не сложились мнения (т.е. как минимум не строго определенное поведение; GCC предупреждает о "possibly unsequenced evaluation" и выдает результат на единицу больше, чем не предупреждающий о подобном CLang; сборка с -std=c++20 -O0 -Wall -Wextra -Werror):

int a{};
++a += a;

В соответствии с [intro.execution], искомое выражение (++a += a) является full-expression и подразбиваемо на подвыражения (условная нотация):
[expr.ass+] (
[expr.pre.incr+] ( a ),
constituent-expression ( a )
)
1. [expr.pre.incr+] модифицирует операнд.
2. [expr.ass+] модифицирует операнд (1, 2).
3. Модификация объекта является побочным эффектом, вычисление подвыражений инициирует их (побочных эффектов) применение.
4. Отношения sequenced-before/sequenced-after между подвыражениями предполагают определенность в их пределах порядка между применением побочных эффектов и вычислением значений.
5. По-умолчанию такой порядок не определен, вытекающие из чего неоднозначности, если возникают, приводят к неопределенному поведению.

В соответствии с описанием упорядоченности вычислений с оператором [expr.ass], вычисление обоих операндов sequenced-before непосредственно присваивания. Кроме того, вычисление правого операнда sequenced-before вычисления левого.
Таким образом представляется, что все надлежащие гарантии упорядоченности присутствуют, а выражение (++a += a) должно выполняться как если бы было переписано нижеследующим образом:
/* constituent-expression ( a ) since rhs is sequenced-before lhs */
int rhs{a};
/* [expr.pre.incr+] ( a ) since lhs is sequenced-after rhs */
++a;
/* [expr.ass+] since assignment is sequenced-after both lhs and rhs */
a += rhs;
Ожидаемым результатом является 1, что соответствует выполнению артефакта от CLang.

Вопрос: где в вышеприведенной логике ошибка, допускающая несогласованность порядка вычисления (учитывая наблюдаемые результаты)? Подобное поведение можно было бы объяснить буквальной (уровня макроподстановок) трактовкой этого положения (поскольку + действительно unsequenced), однако, с другой стороны, для (compound-)assignment предписаны явные гарантии обратного.

35 ответов

26 просмотров

Не делай так

Sergey-Anisimov Автор вопроса

Вот я и хочу узнать, как именно.

Sergey Anisimov
Вот я и хочу узнать, как именно.

Что не делать или что делать? - Разбить выражение на явное указание намерений. - Не писать таких выраженний

Sergey-Anisimov Автор вопроса
Alexey Tkachenko
Что не делать или что делать? - Разбить выражение ...

Так интересно же почему так реализовано в компиляторах.

Sergey Anisimov
Мне бы с т.з. стандарта проблему найти.

реальность не всегда совпадает со стандартом. :)

Вот вам еще квест))) ++a *= a;

Sergey-Anisimov Автор вопроса
Andrew Revvo
Вот вам еще квест))) ++a *= a;

Если для встроенных типов - оно же, с разницей в это и следующее предложения (нерелевантно в рассматриваемом случае).

Sergey Anisimov
Если для встроенных типов - оно же, с разницей в э...

Да пофиг на стандарт gcc и clang не дают никаких варнингов и дают разные результаты)

Sergey-Anisimov Автор вопроса
Andrew Revvo
Да пофиг на стандарт gcc и clang не дают никаких в...

Результаты аналогичны (включая предупреждения при построении с -std=c++20 -O0 -Wall -Wextra -Werror).

кажется, gcc игнорирует, что правая часть должна вычисляться до левой, и делает как-то так: int rhs{++a + a}; a = rhs, а порядок вычисления слагаемых не определен

Sergey-Anisimov Автор вопроса
Vlad
кажется, gcc игнорирует, что правая часть должна в...

Сppinsights тоже, выходит, некорректно разбирает...

Sergey Anisimov
Мне бы с т.з. стандарта проблему найти.

когда в стандарте были точки следования, приведённый код являлся UB, сейчас также, только вместо точек следования какой-то новый способ описания всего этого, охватывающий многопоточку

Sergey-Anisimov Автор вопроса
disba1ancer
когда в стандарте были точки следования, приведённ...

Мы кругами ходим. Если утверждаете, что неопределенность, - пожалуйста, подтверждайте ссылками.

disba1ancer
когда в стандарте были точки следования, приведённ...

этот код содержал неопределенное поведение и после того, как sequence point заменили на sequenced-before. 11 и 14 стандарты

Sergey Anisimov
Мы кругами ходим. Если утверждаете, что неопределе...

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

Vlad
этот код содержал неопределенное поведение и после...

я этого не отрицал, просто правила с точками следования мне показались намного проще

Sergey-Anisimov Автор вопроса

Я про сейчас (хотя бы с семнадцатого).

Sergey Anisimov
Я про сейчас (хотя бы с семнадцатого).

там суть не меняли, просто описали тоже поведение другим способом

если бы точки следования дожили до p0145, то в этом выражении просто добавилось бы sequence point внутри так же, как добавилось sequenced-before отношений

disba1ancer
яннп

все было бы то же самое, что мы имеем сегодня, просто по-другому сформулировано

тут, наверное, прикол не в порядке вычислений

Sergey-Anisimov Автор вопроса

-Wsequence-point на GCC ругается, опять же)

Sergey Anisimov
-Wsequence-point на GCC ругается, опять же)

в доке gcc сказано что-то вроде "оно будет ругаться для совместимости с C"

Sergey-Anisimov Автор вопроса
Alex.Z
в доке gcc сказано что-то вроде "оно будет ругатьс...

Поведение тоже некорректное оказывается.

заметил, что в [expr.ass] используется слово "computation", но не "evaluation", есть какие-либо комментарии по этому поводу

просто в 3ем пункте именно evaluation инициирует побочные эффекты

Sergey-Anisimov Автор вопроса
disba1ancer
просто в 3ем пункте именно evaluation инициирует п...

Вот это интересное наблюдение, конечно. Здесь evaluation (под)выражения (причем с пометкой "in general"!) определяется как value computation (identity determination для glvalue и value fetch для prvalue) и инициация сайд-эффектов. Следом определяется отношение sequenced-before между evaluations (и только ими). Чуть далее отношение определяется для expressions (где value computations и side-effect applications снова разделяются). Т.е. до этого момента отношения упорядоченности выполнения относились исключительно к (и определялись для) вычислению выражений. Наконец, присваивание считается sequenced-after именно value computations для левого и правого операндов, однако сами операнды (подвыражения) все еще называются sequenced-before друг для друга (целиком). Таким образом тоже оказывается любопытно, огрех ли это wording'а для [expr.ass] (и подразумевалась синонимичность), либо же подразумевалось буквально написанное, но не определенное ранее в [intro.execution]...

Sergey Anisimov
Вот это интересное наблюдение, конечно. Здесь eva...

а может сайд эффект быть произведён до вычисления выражения скажем в ++a?

Sergey-Anisimov Автор вопроса
disba1ancer
а может сайд эффект быть произведён до вычисления ...

Инициировано применение должно будет быть при его вычислении, да, однако только sequenced-before/after может гарантировать окончание наложения, а value computation или сайд-эффект (даже инициация, предположительно) для той же memory location без таких гарантий приводит к возникновению неопределенного поведения. Таким образом, если понимать буквально вышеупомянутый вординг [expr.ass], применение сайд-эффектов от левого подвыражения-операнда оказывается unsequenced относительно сайд-эффекта самого присваивания, а т.к. объект (и, транзитивно, memory location) один - UdB. Проблема, однако, в том, что я при изначальном разборе тестировал такой вариант (++a += 1), и он не вызывает ни срабатывания предупреждения, ни различного наблюдаемого поведения на разных компиляторах. Edit: Т.е. возможно это все еще баг поверх стороннего wording issue.

Sergey Anisimov
Инициировано применение должно будет быть при его ...

До 11 стандарта это (я о примере с += 1) однозначно UB, ибо у меня в мозгу железно отложилось правило не меняй переменную более раза между точками следования

Sergey-Anisimov Автор вопроса
disba1ancer
До 11 стандарта это (я о примере с += 1) однозначн...

Рассматриваем в условиях хотя бы семнадцатого.

Похожие вопросы

Обсуждают сегодня

Господа, а что сейчас вообще с рынком труда на делфи происходит? Какова ситуация?
Rꙮman Yankꙮvsky
29
А вообще, что может смущать в самой Julia - бы сказал, что нет единого стандартного подхода по многим моментам, поэтому многое выглядит как "хаки" и произвол. Короче говоря, с...
Viktor G.
2
30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Гайс, вопрос для разносторонее развитых: читаю стрим с юарта, нада выделять с него фреймы с определенной структурой, если ли чо готовое, или долбаться с ринг буффером? нада у...
Vitaly
9
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
14
Добрый день! Скажите пожалуйста, а какие программы вы бы рекомендовали написать для того, чтобы научиться управлять памятью? Можно написать динамический массив, можно связный ...
Филипп
7
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
длина пакета фиксированная, или меняется?
Okhsunrog
7
Карта сайта