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);
    }

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

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

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

(no subject)

From: [personal profile] yigal_s - Date: 2016-10-13 03:40 pm (UTC) - Expand

Хм

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

Date: 2016-10-14 04:59 pm (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
а что там где вывалили?

CppCon 2016

Date: 2016-10-14 06:57 pm (UTC)
From: [identity profile] archaicos.livejournal.com


Обсуждаемое есть на видео в списке (“My Little Optimizer: Undefined Behavior is Magic").

Re: CppCon 2016

From: [personal profile] yigal_s - Date: 2016-10-14 07:09 pm (UTC) - Expand

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: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: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
Собственно на маллок и реаллок оно, возможно даже и не смотрит - ну какая-то там память, оптимизируя только принтф.

(no subject)

From: [identity profile] ormuz.livejournal.com - Date: 2016-10-13 04:24 pm (UTC) - Expand

(no subject)

From: [identity profile] no more turtles - Date: 2016-10-13 10:52 pm (UTC) - Expand

(no subject)

From: [identity profile] no more turtles - Date: 2016-10-13 10:57 pm (UTC) - Expand

(no subject)

From: [personal profile] ak_47 - Date: 2016-10-15 02:16 am (UTC) - Expand

(no subject)

From: [personal profile] ak_47 - Date: 2016-10-15 04:22 am (UTC) - Expand

(no subject)

From: [personal profile] ak_47 - Date: 2016-10-15 06:36 am (UTC) - Expand

(no subject)

From: [personal profile] ak_47 - Date: 2016-10-15 06:41 am (UTC) - Expand

(no subject)

From: [personal profile] ak_47 - Date: 2016-10-15 07:06 am (UTC) - Expand

(no subject)

From: [identity profile] otdiadi.livejournal.com - Date: 2016-10-18 12:58 am (UTC) - Expand

(no subject)

From: [identity profile] otdiadi.livejournal.com - Date: 2016-10-22 12:59 am (UTC) - Expand

Date: 2016-10-15 09:16 pm (UTC)
From: [identity profile] archaicos.livejournal.com
А вот это интереснее.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
  int* p = malloc(sizeof(int));
  uintptr_t ap = (uintptr_t)p;
  int* q = realloc(p, sizeof(int));
//  *p = 1;
  *(int*)ap = 1;
  *q = 2;
//  if (p == q)
  if ((int*)ap == q)
  {
//    printf("%d %d\n", *p, *q);
    printf("%d %d\n", *(int*)ap, *q);
  }
  return 0;
}

Edited Date: 2016-10-15 09:20 pm (UTC)

(no subject)

From: [identity profile] archaicos.livejournal.com - Date: 2016-10-15 10:28 pm (UTC) - Expand

(no subject)

From: [identity profile] archaicos.livejournal.com - Date: 2016-10-15 10:47 pm (UTC) - Expand

(no subject)

From: [identity profile] archaicos.livejournal.com - Date: 2016-10-15 11:18 pm (UTC) - Expand

(no subject)

From: [identity profile] archaicos.livejournal.com - Date: 2016-10-15 11:47 pm (UTC) - Expand

(no subject)

From: [identity profile] archaicos.livejournal.com - Date: 2016-10-15 11:56 pm (UTC) - Expand

(no subject)

From: [identity profile] archaicos.livejournal.com - Date: 2016-10-16 07:13 am (UTC) - Expand

Date: 2016-10-16 12:38 am (UTC)
From: [identity profile] dvv.livejournal.com
Идеальный компилятор должен выдать ошибку компиляции, соптимизировав время выполнения и футпринт программы до нуля.
Edited Date: 2016-10-16 12:40 am (UTC)

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 06:06 am
Powered by Dreamwidth Studios