spamsink: (lenin)
[personal profile] spamsink
Задачка для оптимизирующих программистов (по крайней мере на C++)

В предположении, что компилятор делает все разрешенные стандартом оптимизации, что будет (если будет) напечатано в результате выполнения следующего участка кода (обвязку пишите сами):
    int *p = (int*)malloc(4);
    int *q = (int*)realloc(p, 4);
    *p = 1;
    *q = 2;
    if (p == q) {
        printf("%d %d\n", *p, *q);
    }
Page 1 of 3 << [1] [2] [3] >>

Date: 2016-10-13 08:18 am (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
Строго говоря, будет всё что угодно в пределах возможностей компьютера.

Хм

Date: 2016-10-13 08:21 am (UTC)
From: [identity profile] krakozabr.livejournal.com
Я не оптимизирующий программист.

Но доступные мне (различные) компиляторы делали одно и то же:

2 2

Date: 2016-10-13 08:22 am (UTC)
From: [identity profile] b0p0h0k.livejournal.com
Не вижу причин для не "2 2".

Оговорка: я не сильно много знаю про xx-rated C, так что глядел на это в парадигме C.
Edited Date: 2016-10-13 08:31 am (UTC)

Date: 2016-10-13 08:22 am (UTC)
From: [identity profile] archaicos.livejournal.com
Жулики. Комитетчики и компиляторщики. UB со всеми вытекающими.

Кстати, ролик вышел некоторое время назад (блин, там столько вывалили! смотреть - не пересмотреть), можно было не ходить, а смотреть тюбик в халате и тапках, попивая чай.

Date: 2016-10-13 11:04 am (UTC)
From: [identity profile] febb.livejournal.com
Наверное realloc оставит всё как есть.
Тогда программа напечатает: "2 2\n"

Date: 2016-10-13 11:15 am (UTC)
From: [identity profile] febb.livejournal.com
Интересно что с оптимизацией оно напечатало "1 2\n"
Забавно)

Date: 2016-10-13 11:15 am (UTC)
yurikhan: (Default)
From: [personal profile] yurikhan

Отыгрываю Omniscient Omnipotent Lawful Evil компилятор. Предполагаю sizeof(int) ≤ 4, иначе всё ещё интереснее.

В первой строчке malloc может вернуть nullptr, если памяти нет, или ненулевой указатель на область памяти не менее 4 байт.

Во второй строчке realloc может вернуть (a) nullptr, если p == nullptr и памяти всё ещё нет; (b) указатель p; или же (c) указатель, отличный от p, если реализация стандартной библиотеки не связана ограничением делать все разрешённые оптимизации. В последнем случае указатель p становится невалидным.

В третьей строчке делается разыменование указателя p без проверки, что он не нулевой и валидный, варианты (a) и (c) ведут к UB.

В качестве разрешённой оптимизации предполагаем, что UB не происходит — память всегда есть, а realloc не реаллочит по пустякам. Далее везде считаем, что p == q.

Раз p == q, то запись единицы в третьей строке избыточна. Выоптимизируем её.

В четвёртой строке пишем двойку, если escape-анализ покажет, что значение указателя p или q куда-то выходит из рассматриваемого фрагмента. Если же не выходит, то никто не может легально получить доступ к этой памяти, поэтому запись в память тоже выоптимизируем, а в следующих трёх строчках будем делать вид, что записали.

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

В шестой строке память не читаем. Используем тот факт, что мы только что сделали вид, что записали туда двойку, а переменная не volatile. Форматную строку "%s %s\n" в объектник не пишем, поскольку результат форматирования известен на этапе компиляции. Вызов printf заменяем на puts("2 2\n").

Date: 2016-10-13 03:25 pm (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
Мммм... Позволю себе не согласиться.

Стандарт (да благословит его Аллах) не определяет что такое "оптимизации" и как именно эти оптимизации делаются. Применение оптимизации не меняет наличия или отсутствия UB.

Date: 2016-10-13 03:38 pm (UTC)
From: [identity profile] janatem.livejournal.com
Придумал только такой вариант, который требует извращенного оптимизатора, который «ошибается» в предположениях. Он знает, что размер для realloc() такой же, как у заведенного ранее указателя, поэтому (вообще говоря, ошибочно (?)) предполагает, что realloc() не перемещает указатель. Тогда (корректный вывод) будет выполнено условие p == q, и if можно выбросить. Правда, еще придется предположить, что первый malloc() никогда не возвратит NULL, это уж не знаю, почему может быть (например, оптимизатор заметит, что указатели нигде далее налево не ходят, поэтому можно заменить аллокацию в куче на аллокацию на стеке). Но в реальном запуске выясняется, что (1) оптимизатор ошибся в первом предположении, (2) после освобождения p страница не сдохла, поэтому его можно разыменовывать без сегфолта. Поэтому печатается "1 2".

Date: 2016-10-13 03:40 pm (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
компилятор не "упрощает код", в смысле, не упрощает C++ код. Он оптимизирует результат компиляции _исходного_ кода, именно к исходному коду применяется понятие UB. Но это, пожалуй, вопрос философский и я не уверен, есть ли практический смысл его обсуждать.

Но даже если принять вашу позицию, я не понимаю почему выдачу "1 2" вы считаете детерминистическим результом максимальной оптимизации? Почему, скажем, не "2 2"?

Date: 2016-10-13 03:41 pm (UTC)
From: [identity profile] ormuz.livejournal.com
Strict aliasing rule!

Компилятор может не думать о реаллоке и предпооагает q отдельной областью памяти

Date: 2016-10-13 03:50 pm (UTC)
From: [identity profile] ormuz.livejournal.com
Собственно на маллок и реаллок оно, возможно даже и не смотрит - ну какая-то там память, оптимизируя только принтф.

Date: 2016-10-13 04:24 pm (UTC)
From: [identity profile] ormuz.livejournal.com
realloc возвращает указатель фундаментально отличающийся от q.
С точки зрения стандарта, насколько я понимаю, это как удалить старый обьект, создать новый обьект.

Вероятно, если передать , p и q как параметры, то оптимизировать так уже нельзя

Date: 2016-10-13 06:40 pm (UTC)
From: [identity profile] archaicos.livejournal.com
Стандарт говорит очень забавно, примерно как «Видишь кролика? Нет? А он есть!». С одной стороны, указатель не меняется, но с другой стороны формально жизнь не очень-то существовавшего объекта прерывается, и формально же указатель перестаёт указывать туда, куда он продолжает указывать. Форменное издевательство!
Page 1 of 3 << [1] [2] [3] >>

Profile

spamsink: (Default)
spamsink

February 2026

S M T W T F S
12345 67
8 91011 121314
15161718 192021
22 2324 25262728

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Mar. 5th, 2026 07:33 am
Powered by Dreamwidth Studios