Манипуляции с динамической памятью на Си (хочется достичь страшной красоты со страшной силой)

Модератор: Модераторы разделов

dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Манипуляции с динамической памятью на Си

Сообщение dimbor »

Речь пойдет о красоте, сиречь читаемости кода. При выделении памяти под переменную, ее надо потом освобождать (кэп одобряэ). Конструкции if(a) free(a); с точки зрения читаемости большого и светлого реализуемого алгоритма являются несколько мусорными что-ли.
С тех пор как узнал про alloca(), внутри блоков стало все хорошо. Может и не оптимально, зато читается код с легкостью. Оптимизация - это потом, сначало требуется родить и отладить.
Но вот имеется например функция, возвращающая динамическую строку (malloc()) :
char *sDogName(void);

Вызывается так:

Код: Выделить всё

char *sCurrentDog=sDogName();
if (!PatterHasDog(sCurrentDog)) {
   if (sCurrentDog)
      free(sCurrentDog);
   return FAIL;
}
MakeLoveWithHim(sCurrentDog);
...
free(sCurrentDog);


С точки зрения читаемости строки фрагмента с третьей по пятую явно лишние. А еще там дальше кроме PatterHasDog() имеются вызовы RebeHasDog(), AnybodyHasDog(),... И все с аналогичными вызовами и реакцией.

По зелености меня как сишника, пока для наведения красоты в голову приходит только макрос типа

Код: Выделить всё

#define FREE_AND_RET_FAIL(s) { \
   if (s)                           \
      free(s);                   \
   return FAIL;              \
}


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

Код: Выделить всё

char *sCurrentDog=sDogName();
if (!PatterHasDog(sCurrentDog))
   FREE_AND_RET_FAIL(sCurrentDog);
MakeLoveWithHim(sCurrentDog);
...
free(sCurrentDog);


Не придумал ли я неведомую фигню? Кто как решает подобные вопросы? А то правда запарили лишние строчки и скобки. Полгода пройдет, и в собственной писанине как в чужой приходится разбираться.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Манипуляции с динамической памятью на Си

Сообщение NickLion »

1. #define блок лучше заключать в do { ... } while(0), а не просто {...}.
2. По стандарту если аргумент функции free равен NULL, то free просто ничего не делает, т.е. if (s) free(s) равносильно free(s).
3. А оно надо 1 строчку с return экономить? Тем более, что если коды ошибок будут разные, то макрос уже не нужен.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение eddy »

Не надо return запихивать в макрос.

Я такие штуки, где надо проверять разные условия и, если что, очищать разные куски памяти, просто ставлю в конце функции кучу меток и соответствующие действия. Если там только free, то метка одна, а за ней - куча free. Вот так просто: проверяем условие, не годится - goto в конец функции.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Re: Манипуляции с динамической памятью на Си

Сообщение dimbor »

NickLion писал(а):
20.11.2012 20:39
1. #define блок лучше заключать в do { ... } while(0), а не просто {...}.

Благодарю, полезно. Это из-за запяточия, в смысле точки с запятой?

NickLion писал(а):
20.11.2012 20:39
2. По стандарту если аргумент функции free равен NULL, то free просто ничего не делает, т.е. if (s) free(s) равносильно free(s).

Это тоже интересная информация для меня. Насколько свежий стандарт? C99? А то смотрю например код старого шестого Xorg - там сплошь и рядом. Ну и я туда же, как обезьяна.

NickLion писал(а):
20.11.2012 20:39
3. А оно надо 1 строчку с return экономить? Тем более, что если коды ошибок будут разные, то макрос уже не нужен.

Ну макрос схематично написан, для представления идеи. На самом деле туда параметром идет и тот самый код ошибки, а остальных параметров - переменное количество. Все по букварю.
Насчет экономии одной строчки - копейка рупь бережет, и экономика должна быть экономной ©. Сподобился на писание не так давно, но чужого кода пришлось прочитать жуткие бегамайты. И получается, один код написал, потом трое пропатчили. Причем один отступал пробелами, другой табуляцией, а третий - вообще не парился. И лови потом эти скобки до о..стервенения.
Посему поимел мнение, что желательно выделять операторными скобками логические блоки, а не технические.
Спасибо сказали:
dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Re: Манипуляции с динамической памятью на Си

Сообщение dimbor »

eddy писал(а):
20.11.2012 21:44
Не надо return запихивать в макрос.

Я такие штуки, где надо проверять разные условия и, если что, очищать разные куски памяти, просто ставлю в конце функции кучу меток и соответствующие действия. Если там только free, то метка одна, а за ней - куча free. Вот так просто: проверяем условие, не годится - goto в конец функции.

Как жестко воспитанный адепт структурного программирования набрал воздуха для вопля. Но призадумался.
С другой же стороны, оно что ни ешь, на выходе все одно получается. Нда. Машинный код в смысле, где этих переходов..
А если в один макрос засунуть goto вместо return, другой же обозвать CLЕANING_AT_END_OF_FUNC(a, ...), засунуть туда метку, очистку параметров в цикле, всех, что передадут? В таком случае получается великолепной надежности уборщик-гастрабайтер. И вроде все на вид стуктурным канонам остается отвечать.

Как оно? Но в любом случае, за идею - респект!
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Манипуляции с динамической памятью на Си

Сообщение NickLion »

dimbor писал(а):
20.11.2012 21:47
NickLion писал(а):
20.11.2012 20:39
1. #define блок лучше заключать в do { ... } while(0), а не просто {...}.

Благодарю, полезно. Это из-за запяточия, в смысле точки с запятой?

Да. Например, в if:

Код: Выделить всё

if (a) MULTI_MACRO(); else ...

Если MULTI_MACRO развернётся в {...}, то получится

Код: Выделить всё

if (a) {...}; else ...
и результат будет далёк от ожидаемого.

dimbor писал(а):
20.11.2012 21:47
Это тоже интересная информация для меня. Насколько свежий стандарт? C99? А то смотрю например код старого шестого Xorg - там сплошь и рядом. Ну и я туда же, как обезьяна.

Точно C99, C11, POSIX
Вроде в C89/90 так же было, но под рукой древнего стандарта нет.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение eddy »

dimbor писал(а):
20.11.2012 22:42
Но в любом случае, за идею - респект!

Это - не моя идея, она стара, как мир C.

А вот о сборщике мусора я одно время думал. Можно его на макросах реализовать, но сложно. Проще вручную все контролировать.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение drBatty »

dimbor писал(а):
20.11.2012 21:47
Это тоже интересная информация для меня. Насколько свежий стандарт?

оно лучше-бы не в стандарте смотреть, а в man 3 free
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc()
or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is
performed.

...

CONFORMING TO
C89, C99.

dimbor писал(а):
20.11.2012 19:54
С тех пор как узнал про alloca(), внутри блоков стало все хорошо. Может и не оптимально, зато читается код с легкостью.

глючное РЕШЕТО. Причём тут "оптимальность"? Вопрос в том, что это для другого память вообще-то. Вам ДОКАЗЫВАТЬ надо, что это за стек не вылезет! (кста, сколько у вас стек?)

http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Манипуляции с динамической памятью на Си

Сообщение NickLion »

drBatty писал(а):
23.11.2012 21:27
оно лучше-бы не в стандарте смотреть, а в man 3 free

Точно! man 3p free глянул, а 3 не додумался
Спасибо сказали:
dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Re: Манипуляции с динамической памятью на Си

Сообщение dimbor »

drBatty писал(а):
23.11.2012 21:27
dimbor писал(а):
20.11.2012 19:54
С тех пор как узнал про alloca(), внутри блоков стало все хорошо. Может и не оптимально, зато читается код с легкостью.

глючное РЕШЕТО. Причём тут "оптимальность"?

И не надо так кричать. И так категорично. Тем более, что мое "Может и не оптимально" - предположение, крайне созвучное вашему утверждению.
Тем более, раз за alloca(), видимо, убивают мучительно. Ну значит придется от нее избавляться в той же макросной системе, которая тут обсуждается.

drBatty писал(а):
23.11.2012 21:27
Вопрос в том, что это для другого память вообще-то. Вам ДОКАЗЫВАТЬ надо, что это за стек не вылезет! (кста, сколько у вас стек?)

Я вообще-то уже все себе доказал лет -дцать как, молодой человек. А ответ на нескромный вопрос будет всего 12-13 в эрегированном состоянии. ;)

ЗЫ: Не в обиду, точно также выдрал фразу из контекста и категорично на нее ответил. Алаверды типа.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение eddy »

dimbor писал(а):
23.11.2012 22:30
Тем более, раз за alloca(), видимо, убивают мучительно.

Некоторые экземпляры еще и категорично говорят: «Вах, у тебя goto, ты — быдло!»
А копнули бы они поглубже, да почитали оригинал, в котором понятным образом описывается, почему в некоторых случаях лучше goto не использовать, а в остальных — всегда пожалуйста!

// тоже выдрал из контекста
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение drBatty »

dimbor писал(а):
23.11.2012 22:30
И не надо так кричать. И так категорично. Тем более, что мое "Может и не оптимально" - предположение, крайне созвучное вашему утверждению.

если вам нужен сборщик мусора - сделайте себе кошерный сборщик мусора. Не вижу проблемы. Просто стек и куча это очень _разные_ памяти. Стек - небольшая и близкая, а куча - большая и медленная. В куче есть смысл хранить большое количество больших объектов, а в стеке - небольшое количество мелких. Проблема в том, что компилятор очень любит пихать временные данные в стек, и создатели CPU потому делают верхушку стека рядом с ALU. А если в стек засунуть что-то большое, то компилятор всё равно будет туда пихать, и это приведёт к тому, что часть данных будет далеко, и обращаться за ними будет очень дорого, но компилятор об этом не в курсе. К тому же, есть вероятность, что данные не влезут в стек, который по "славной" традиции C/C++ никто не проверяет. Это будет очень печально.
dimbor писал(а):
23.11.2012 22:30
Тем более, раз за alloca(), видимо, убивают мучительно. Ну значит придется от нее избавляться в той же макросной системе, которая тут обсуждается.

вот не надо утрировать! alloca() полезная и нужная штука, сколько раз говорить про гвозди и шурупы?! И макросы - хорошая штука. Но всё должно быть к месту.
dimbor писал(а):
23.11.2012 22:30
Я вообще-то уже все себе доказал лет -дцать как, молодой человек. А ответ на нескромный вопрос будет всего 12-13 в эрегированном состоянии.

за "молодой человек" - спасибо. Давно никто так не называл...
про "нескромные вопросы" - совсем не в тему. Проблема как раз в том, что куча имеет свойство расширяться, а вот стек такого свойства НЕ имеет. Потому пихать данные в кучу сравнительно безопасно - если у вас слабая система, то вы вправе ожидать маленькие данные и маленькую кучу, если сильные, то и данные большие, но и куча тоже, к тому-же куча обычно "резиновая", когда туда большой массив пихаешь, она как резина растягивается, на величину свопа. Оно конечно тормозит вставку, но... Это лучше чем стек, который ВНЕЗАПНО рвётся, как стеклянный. Глючная программа жрущая память завязнет в свопе, и будет аккуратно остановлена OOM Killer'ом, но программа жрущая стек приводит к _непредсказуемым_ последствиям.
eddy писал(а):
24.11.2012 01:25
Некоторые экземпляры еще и категорично говорят: «Вах, у тебя goto, ты — быдло!»
А копнули бы они поглубже, да почитали оригинал, в котором понятным образом описывается, почему в некоторых случаях лучше goto не использовать, а в остальных — всегда пожалуйста!

немного не так: в _некоторых_ случаях goto использовать есть смысл, во всех остальных - это приводит к нечитаемому быдлокоду. Goto есть смысл использовать для выхода из вложенных циклов, т.к. break выходит только из одного. Если надо завершить сразу два, то без goto это будет дороже (придётся либо ставить ещё проверку, либо использовать return). Это редко встречается. Какие ещё есть оправданные случаи goto? Я(по молодости) других не встречал. Расскажите, если знаете. (кстати в bash goto нет, за то break/continue можно использовать с параметром).
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение eddy »

drBatty писал(а):
24.11.2012 04:21
Какие ещё есть оправданные случаи goto?

Как в примере: если надо организовать сборщик мусора на выходе из функции. Например, завершился очередной malloc с ошибкой → выходим из функции, предварительно подчистив все, чтобы утечек не было.
А это можно сделать либо при помощи goto, либо при помощи функции в функции (что, по сути, - то же goto, но с возвратом в точку вызова, т.е. еще и return придется впихивать).
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Re: Манипуляции с динамической памятью на Си

Сообщение dimbor »

Значит далее шагаю по граблям

eddy писал(а):
21.11.2012 08:40
Это - не моя идея, она стара, как мир C.

По тематике раздела все новое - хорошо невыученное старое.

eddy писал(а):
21.11.2012 08:40
А вот о сборщике мусора я одно время думал. Можно его на макросах реализовать, но сложно. Проще вручную все контролировать.


А я все-таки сделал "велосипедную" попытку с учетом высказанных нравоучений.

Еще раз о целях:
  • Эстетическо-гигиеническая - освободить код от порой многострочных и многоскобочных конструкций освобождения динамических ресурсов.
  • Склеротическая - все, что явно/неявно выделяется и наружу не выходит, должно быть гарантированно убито на выходе.
  • Код должен удовлетворять структурные каноны. Хотя бы на первый взгляд.


От задумки вариативного макроса CLЕANING_AT_END_OF_FUNC(...) отказался. Первая беда тут маленькая: Из-за принципиальной невозможности посчитать количество вариативных параметров, надо загибать пальцы, считая переменные, и передавать еще и их количество вначале. Ну или какой-нить якорь в конце.
Вторая же беда ставит на затее жирный крест. Сплошь и рядом в коде встречается { sometype *var=...; ...} - видимость в блоке.
Компилятор не поймет эту var снаружи.

Значит остается вариант диспетчера памяти лайт. В рамках отдельно взятой функции.

Код: Выделить всё

#define FUNC_START(typeret)        \
    int cnt_refs_=0, sz_refs_=0;        \
    void **ref_=NULL;                \
    typeret retval_

#define NEWREF(ptr)   do {                \
    if (cnt_refs_ == sz_refs_) {            \
        sz_refs_+=8;                    \
        ref_=realloc(ref_,sz_refs_);        \
    }                                \
    ref_[cnt_refs_]=ptr;                \
    cnt_refs_++;                        \
} while(0)

#define FRET(retval) do {            \
    retval_=retval;                \
    goto end_;                    \
} while(0)

#define FUNC_END()                      \
    end_:                            \
        for (int i=0; i<cnt_refs_; i++)    \
            free(ref_[i]);                \
        free(ref_);                    \
        return retval_


Тогда реализация начала церковно-собачей считалочки будет выглядеть так:

Код: Выделить всё

FUNC_START(int);
char *sCurrentDog=sDogName(); NEWREF(sCurrentDog);
if (!PatterHasDog(sCurrentDog))
   FRET(0);
MakeLoveWithHim(sCurrentDog);
...
FUNC_END();


Минус - в стартовом макросе надо писать тип возвращаемого значения. Не нашел, как заставить препроцессор подставлять его неявно. А если void на выходе, то надо как-то исхитряться. Как?
Особенность - про return надо забыть. За него FRET().
Скорее плюс - регистрируя новопоявившюся динамику посредством NEWREF(), про нее далее тоже можно забыть - пришибется (типа удар отсроченной смерти ;)).
Вопрос - метка где уникальна, в блоке или файле? Если в файле, надо ее как-то персонифицировать, а __func__ в макросе не ракрывается.

А теперь буду благодарен за брошенные в мну какашки.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение eddy »

dimbor писал(а):
24.11.2012 16:55
А теперь буду благодарен за брошенные в мну какашки.

Получилась тяжелая штука, не гарантирующая, что вы где-нибудь не забудете вместо return написать FRET или воткнуть FUNC_END() в конце.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение drBatty »

eddy писал(а):
24.11.2012 12:03
Как в примере: если надо организовать сборщик мусора на выходе из функции. Например, завершился очередной malloc с ошибкой → выходим из функции, предварительно подчистив все, чтобы утечек не было.

это TCO, его умеет gcc, т.ч. можно писать call/ret, это выглядит красиво и кошерно, а накладных расходов тут нет. Т.ч. не принимается.
вот например:

Код: Выделить всё

080484f0 <free1>:
 80484f0:       a1 b4 98 04 08          mov    eax,ds:0x80498b4
 80484f5:       85 c0                   test   eax,eax
 80484f7:       74 0e                   je     8048507 <free1+0x17>
 80484f9:       83 ec 1c                sub    esp,0x1c
 80484fc:       89 04 24                mov    DWORD PTR [esp],eax
 80484ff:       e8 3c fe ff ff          call   8048340 <free@plt>
 8048504:       83 c4 1c                add    esp,0x1c
 8048507:       c3                      ret
 8048508:       90                      nop
 8048509:       8d b4 26 00 00 00 00    lea    esi,[esi+eiz*1+0x0]

08048510 <foo>:
 8048510:       83 ec 1c                sub    esp,0x1c
 8048513:       c7 04 24 0a 00 00 00    mov    DWORD PTR [esp],0xa
 804851a:       e8 b1 ff ff ff          call   80484d0 <alloc1>
 804851f:       8b 15 b4 98 04 08       mov    edx,DWORD PTR ds:0x80498b4
 8048525:       31 c0                   xor    eax,eax
 8048527:       89 f6                   mov    esi,esi
 8048529:       8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]
 8048530:       89 04 82                mov    DWORD PTR [edx+eax*4],eax
 8048533:       40                      inc    eax
 8048534:       83 f8 0a                cmp    eax,0xa
 8048537:       75 f7                   jne    8048530 <foo+0x20>
 8048539:       c7 05 b8 98 04 08 00    mov    DWORD PTR ds:0x80498b8,0x0
 8048540:       00 00 00
 8048543:       30 c0                   xor    al,al
 8048545:       eb 0f                   jmp    8048556 <foo+0x46>
 8048547:       89 f6                   mov    esi,esi
 8048549:       8d bc 27 00 00 00 00    lea    edi,[edi+eiz*1+0x0]
 8048550:       8b 15 b4 98 04 08       mov    edx,DWORD PTR ds:0x80498b4
 8048556:       8b 04 82                mov    eax,DWORD PTR [edx+eax*4]
 8048559:       89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 804855d:       c7 04 24 60 86 04 08    mov    DWORD PTR [esp],0x8048660
 8048564:       e8 c7 fd ff ff          call   8048330 <printf@plt>
 8048569:       a1 b8 98 04 08          mov    eax,ds:0x80498b8
 804856e:       40                      inc    eax
 804856f:       a3 b8 98 04 08          mov    ds:0x80498b8,eax
 8048574:       83 f8 09                cmp    eax,0x9
 8048577:       7e d7                   jle    8048550 <foo+0x40>
 8048579:       c7 04 24 0a 00 00 00    mov    DWORD PTR [esp],0xa
 8048580:       e8 fb fd ff ff          call   8048380 <putchar@plt>
 8048585:       83 c4 1c                add    esp,0x1c
 8048588:       e9 63 ff ff ff          jmp    80484f0 <free1>

Код: Выделить всё

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

static int *p = NULL;

void alloc1(int n)
{
    p = malloc(sizeof(int)*n);
}



void free1()
{
    if(!p)
        return;
    free(p);
}

void foo()
{
    alloc1(10);
    static int j;
    for(j = 0; j < 10; j++)
        p[j] = j;
    for(j = 0; j < 10; j++)
        printf("%d ", p[j]);
    printf("\n");
    free1();
}

int main()
{
    foo();
    return 0;
}

очевидно, что TCO сработает лишь если TC не имеет параметра (у меня такой тривиальный сборщик мусора собирающий 1 переменную)
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение drBatty »

dimbor
вот вам ради прикола простой сборщик мусора:
http://pastebin.com/L71Lcfcb
суть такова: в начале блока выделяете данные alloc_begin(), потом alloc_continue(). В конце блока очищаете память free_block()

PS: конечно можно добавить контроль выделения/освобождения и прочие нужные фишки. Это всего лишь концепт. И конечно на C++ всё было-бы проще, ибо там есть конструкторы, и деструкторы, т.е. нужда в free_block() отпадёт.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Re: Манипуляции с динамической памятью на Си

Сообщение dimbor »

drBatty писал(а):
24.11.2012 20:12
вот вам ради прикола простой сборщик мусора:

Благодарю, осмотрел. Вроде как по принципу действия от моего "макросного" не отличается (особенно после того, как я в своем ошибки исправил, и он заработал). Только если мой тяжелый, то этот-то какой? Хотя забираю вопрос взад - еще этот есть.

eddy писал(а):
24.11.2012 17:38
Получилась тяжелая штука, не гарантирующая, что вы где-нибудь не забудете вместо return написать FRET или воткнуть FUNC_END() в конце.

Облегчить можно, если выделять фиксированный max размер массива указателей в FUNC_START. Можно его очистку в отдельную функцию вытащить, хотя тут сомневаюсь в экономии.
От забывчивости отчасти спасет придумывание способа задания уникальных меток на каждую функцию.
А гарантирует на 100% у нас пока только фирма "Ритуал", да и у той по смутным слухам были проколы.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение drBatty »

dimbor писал(а):
24.11.2012 22:13
Благодарю, осмотрел. Вроде как по принципу действия от моего "макросного" не отличается (особенно после того, как я в своем ошибки исправил, и он заработал). Только если мой тяжелый, то этот-то какой?

мой полегче. хотя-бы потому, что мой использует связанный список связанных списков, а вовсе не _очень_ медленный макрос realloc(). Этот макрос плох тем, что сбивает аллокатор с толку, он оптимизирован на то, что кусок памяти не будет расти, и мало того, обычно ещё и на LIFO. Я не делал замеров, но уверен, что мой вариант будет быстрее в разы. Ну и кроме того, мой вариант не использует макросы, а это уже плюс.

dimbor писал(а):
24.11.2012 22:13
Хотя забираю вопрос взад - еще этот есть.

там 3 года разбираться. проще с нуля написать.
dimbor писал(а):
24.11.2012 22:13
Облегчить можно, если выделять фиксированный max размер массива указателей в FUNC_START.

вы же понимаете, что это не выход...
dimbor писал(а):
24.11.2012 22:13
От забывчивости отчасти спасет придумывание способа задания уникальных меток на каждую функцию.
А гарантирует на 100% у нас пока только фирма "Ритуал", да и у той по смутным слухам были проколы.

а вот моё решение даёт такую гарантию: предположим, что вы забыли где-то free_block(). Что при этом произойдёт? Да ничего - просто уровни будут возвращаться не сразу после выхода из блока, а с задержкой на 1 уровень. В конце работы программы останется лишний не удалённый уровень, что можно легко обнаружить, и выдать диагностическое сообщение. На работу это не повлияет никак, кроме небольшого перерасхода памяти.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Re: Манипуляции с динамической памятью на Си

Сообщение dimbor »

drBatty писал(а):
25.11.2012 02:39
dimbor писал(а):
24.11.2012 22:13
Облегчить можно, если выделять фиксированный max размер массива указателей в FUNC_START.

вы же понимаете, что это не выход...

С точки зрения академической си-шности конечно не выход. Но стрелять из пушки моими поделиями все равно не будут. Да и Ваши замечания при всей их правильности и полезности несколько уводят в сторону от основного ядрышка топика.
Напомню, оно примерно звучит: "Запарили эти скобки не по делу. Как бы от них избавиться."
Опять же, покажите хоть одного, который советов тут слушается. ;)
Так вот, с учетом потребностей, возможностей и пожеланий родился вариант (даже два на выбор), который меня устроит.

Код: Выделить всё

/* fixed amount of controlled variables */
#define MAX_DYN_VARS_AT_FUNC 8

#define V_START()                        \
    int cnt_myrefs_=0;                    \
    void *myref_[MAX_DYN_VARS_AT_FUNC]

#define F_START(typeret,def_ret)        \
    V_START();                            \
    typeret myretval_=def_ret

/* max amount of ctrl variables - as a parameter */
#define V_START_A(max_refs)            \
    int cnt_myrefs_=0;                    \
    void *myref_[max_refs]

#define F_START_A(typeret,def_ret,max_refs)    \
    V_START_A(max_refs);                        \
    typeret myretval_=def_ret

#define NREF(ptr)   do {                \
    myref_[cnt_myrefs_]=ptr;            \
    cnt_myrefs_++;                        \
} while(0)

#define VRET() do {                \
    goto end_;                        \
} while(0)

#define FRET(retval) do {            \
    myretval_=retval;                \
    goto end_;                        \
} while(0)

#define V_END()                            \
    end_:                                    \
        for (int i=0; i<cnt_myrefs_; i++)    \
            free(myref_[i])

#define F_END()                        \
    V_END();                        \
    return myretval_


Да, - пищу, но лезу. Соответственно, теперь бобика умучивать надо так:

Код: Выделить всё

F_START(int,1);
char *sCurrentDog=sDogName(); NREF(sCurrentDog);
if (!PatterHasDog(sCurrentDog))
   FRET(0);
MakeLoveWithHim(sCurrentDog);
...
F_END();

Для других пород фукциий, не возвращающих ничего, предназначены макросы с префиксом V, а для отдельных функций, жадных до количества динамических переменных - макросы с суффиксом A. Естественно, в реальном использовании FRET редок. Как правило, обернут макросом типа FATAL_RET(val, logfmt, ...), но это уже совсем другая история.

Еще раз благодарю всех откликнувшихся!
Спасибо сказали:
Аватара пользователя
deadhead
Сообщения: 1913
Статус: zzz..z

Re: Манипуляции с динамической памятью на Си

Сообщение deadhead »

drBatty писал(а):
24.11.2012 04:21
Проблема в том, что компилятор очень любит пихать временные данные в стек
полько при достаточном регистровом давлении...
drBatty писал(а):
24.11.2012 04:21
создатели CPU потому делают верхушку стека рядом с ALU
о какой архитектуре идет речь?

[x] close
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Манипуляции с динамической памятью на Си

Сообщение NickLion »

*в приступе борьбы за истинность терминологии*
Пожалуйста, не называйте больше обсуждаемое сборщиком мусора. Даже умные указатели (реализующие более свободное использование памяти, чем приведённое тут), не могут называться сборщиком мусора (хотя иногда именуют "сборщиком мусора на подсчёте ссылок", но он предоставляет более ограниченный функционал). Так что это в лучшем случае local scope automatic memory managment.
Спасибо сказали:
dimbor
Ведущий рубрики
Сообщения: 1569
Статус: Подвинутый участник

Re: Манипуляции с динамической памятью на Си

Сообщение dimbor »

NickLion писал(а):
28.11.2012 08:52
*в приступе борьбы за истинность терминологии*
Пожалуйста, не называйте больше обсуждаемое сборщиком мусора.

Где-то я уже встречал подобный ход сюжета. Точно: Яхту назвали "ПОБЕДА". Как назвали, так и поплыла. Но все же "отставить макать капитана!" ©
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение drBatty »

dimbor писал(а):
27.11.2012 23:46
"Запарили эти скобки не по делу. Как бы от них избавиться."

да? вам скобки не нравятся? а мне макросы. я их ЛЮТО, БЕШЕНО НЕНАВИЖУ!!!
dimbor писал(а):
27.11.2012 23:46
родился вариант (даже два на выбор), который меня устроит.

я-бы повесился поддерживая код, где goto в макросах.


deadhead писал(а):
28.11.2012 06:07
о какой архитектуре идет речь?

я нагуглил про itanium, в новых процесорах ИМХО тоже что-то подобное. Но не нагуглил. Поможете?
deadhead писал(а):
28.11.2012 06:07
при достаточном регистровом давлении...

ax, bx,cx,dx,si,di
собственно ВСЕ регистры. Причём у каждого есть _уникальное_ свойство, а часто не одно. Т.ч. в x86 с регистрами проблема была, есть и будет.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение eddy »

drBatty писал(а):
28.11.2012 23:31
а мне макросы. я их ЛЮТО, БЕШЕНО НЕНАВИЖУ!!!

Ужаснись: я в CGI делаю так:

Код: Выделить всё

#define         _LANG(_var, _ru, _en)   char _var##ru[] = _ru;\
                                        char _var##en[] = _en;\
                                        char *_var[2] = {_var##ru,  _var##en};
#define         _L(x)   (x[Lang])
…

http://code.google.com/p/bta-meteo-logger/...C/daemon/lang.h

Использовать gettext в CGI — накладно, поэтому двуязычность реализую так.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Манипуляции с динамической памятью на Си

Сообщение NickLion »

drBatty писал(а):
28.11.2012 23:31
я нагуглил про itanium, в новых процесорах ИМХО тоже что-то подобное. Но не нагуглил. Поможете?

В x86 вроде бы никакой особой оптимизации для стека нет. Стандартная кэш-память только. А поскольку верхушка стека будет использоваться часто, то скорее всего она там будет.

drBatty писал(а):
28.11.2012 23:31
ax, bx,cx,dx,si,di
собственно ВСЕ регистры. Причём у каждого есть _уникальное_ свойство, а часто не одно. Т.ч. в x86 с регистрами проблема была, есть и будет.

16 битная архитектура? Жестоко ;) eax, ebx, ecx, edx, esi, edi для 32-битной архитектуры. Да маловато, только кэш и спасает. А вот уникальных свойств намного меньше стало для этих регистров. В x86_64 посвободнее будет на 8 регистров: rax, rbx, rcx, rdx, rsi, rdi, r8–r15.
Спасибо сказали:
Аватара пользователя
deadhead
Сообщения: 1913
Статус: zzz..z

Re: Манипуляции с динамической памятью на Си

Сообщение deadhead »

drBatty писал(а):
28.11.2012 23:31
я нагуглил про itanium, в новых процесорах ИМХО тоже что-то подобное. Но не нагуглил. Поможете?
ваше утверждение вы и "гуглите"... я так первый раз об этом слышу...и вы, видимо, тоже раз гуглить пришлось ;)
drBatty писал(а):
28.11.2012 23:31
Причём у каждого есть _уникальное_ свойство, а часто не одно.
спасибо, кэп!
drBatty писал(а):
28.11.2012 23:31
Т.ч. в x86 с регистрами проблема была, есть и будет.
не одним x86 живы...
[x] close
Спасибо сказали:
Аватара пользователя
Crazy
Сообщения: 862
Статус: Адепт Дзен.
ОС: Mint, Win7.

Re: Манипуляции с динамической памятью на Си

Сообщение Crazy »

eddy писал(а):
29.11.2012 00:29
Использовать gettext в CGI — накладно, поэтому двуязычность реализую так.

Насколько накладно?

Desipere in loco
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение eddy »

Crazy писал(а):
29.11.2012 11:39
eddy писал(а):
29.11.2012 00:29
Использовать gettext в CGI — накладно, поэтому двуязычность реализую так.

Насколько накладно?

Не засекал разницу. Надо будет как-нибудь тест провести. Ведь что такое gettext - это обычный strstr, который в массиве ищет нужную строку, а потом из другого массива с тем же индексом берет перевод.
А этот подход не требует индексы искать, все уже готово.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Манипуляции с динамической памятью на Си

Сообщение drBatty »

eddy
eddy писал(а):
29.11.2012 00:29
Ужаснись

уже:
eddy писал(а):
29.11.2012 00:29
KOI8-R - патриотичная кодировка



NickLion писал(а):
29.11.2012 06:56
16 битная архитектура? Жестоко

ну пусть будет rax, rbx, rcx, rdx и т.д. Какая разница?
deadhead писал(а):
29.11.2012 10:39
ваше утверждение вы и "гуглите"... я так первый раз об этом слышу...и вы, видимо, тоже раз гуглить пришлось ;)

нираспарсил. вы-то что нагуглили? или тоже ничего?

deadhead писал(а):
29.11.2012 10:39
не одним x86 живы...

а чем ещё?
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Ответить