LINUX.ORG.RU

[C] Динамический массив

 


0

0

Захотелось сабжа. Недолго думая наваял несколько макросов. 
Я их даже не тестировал и не компилировал примеры с ними, а V_SET даже и не 
написан полностью (потому и приводить не буду - и так многабукаф), но, думаю, мысль основная ясна. 
Подразумевается возможность ловли ошибок и просто событий в передаваемый кэллбак. 
Остальное ясно из кода. Вопросов несколько:
1. Имеет ли право на существование такой код, или лучше переписать
всё на функциях (тип элемениов тупо void * и всё)?
2. Может комбинированный вариант (макросы типо DECLARE_FUNC_SET
(name,type), которые определяют функцию с нужными типами, но есть и 
выигрыш в размере результирующего кода (за счёт использования функций)).
3. Ну и естественно - ваш вариант :).
================================
enum vec_event_e {
    vec_event_SET               = 0x01,
    vec_event_GET               = 0x02,
    vec_event_INIT              = 0x04,
    vec_event_DESTROY           = 0x08,
    vec_event_OUT_OF_RANGE      = 0x10,
    vec_event_NOT_ENOUGH_MEMORY = 0x20,
    vec_event_ALL               = 0x3f,
};

enum grow_type_e { grow_type_ADD, grow_type_MUX };

#define DECLARE_VECTOR(name,type,null_elem,init_count) \
    struct name##_s {                   \
        type mas[(init_count)]={0};     \
        int el_st_count = (init_count); \
        type * values = NULL;           \
        type el_null = (null_elem);     \
        int el_last_idx = 0;            \
        int el_alloc = (init_count);    \
        int grow = 0;                   \
        enum grow_type_e gr_type = 0;   \
        vec_event_e e_mask = 0;         \
        void (* log_f)(char * nm,       \
                vec_event_e ev, char * file,    \
                char * func, int line) = NULL;  \
    } name;

#define INIT_VECTOR(name, grow_type, grow_val, ev_mask, logf)   \
    do {                            \
        name.values = name.mas;     \
        name.grow = (grow_val);     \
        name.gr_type = (grow_type); \
        name.e_mask = (ev_mask);    \
        name.log_f = (logf);        \
        if(name.log_f && (name.e_mask & vec_event_INIT)){\
            name.log_f(#name, vec_event_INIT,       \
                    __FILE__, __func__, __LINE__);  \
        }\
    }while

#define DESTROY_VECTOR(name)        \
    do {                            \
        if(name.values != name.mas){\
            free(name.values);      \
            name.values = NULL;     \
        }                           \
        name.el_last_idx = 0;       \
        name.el_alloc = sizeof(name.mas)/sizeof(name.mas[0]);\
        name.grow = 0;              \
        if(name.log_f && (name.e_mask & vec_event_DESTROY)){\
            name.log_f(#name, vec_event_DESTROY,            \
                    __FILE__, __func__, __LINE__);          \
        }                                                   \
        name.e_mask = 0;            \
        name.log_f = NULL;          \
    }while

#define V_GET(name, pos)                        \
    ((name.el_last_idx>=(pos)) && ((pos)>0)) ?  \
            do{                                             \
                if(name.log_f && (name.e_mask & vec_event_GET)){\
                    name.log_f(#name, vec_event_GET,        \
                            __FILE__, __func__, __LINE__);  \
                }                                           \
            }while, name.values[pos] :                      \
            do{                                             \
                if(name.log_f && (name.e_mask &             \
                        (vec_event_GET | vec_event_OUT_OF_RANGE))){\
                    name.log_f(#name, vec_event_GET | vec_event_OUT_OF_RANGE,\
                            __FILE__, __func__, __LINE__);  \
                }                                           \
            }while, name.el_null;


★★

смешались в кучу кони люди

логирование то тут каким боком :-? если вдруг STL захочет что-то выводить на stdout я буду первым, кто кинет в неё камень.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> логирование то тут каким боком :-?
Да не хошь - передавай в INIT_VECTOR NULL заместо logf - и всё будет работать без логирования. А мне мож статистику собрать охота - тут изменения можно будет вносить "более централизованно". Ну да не в этом суть. Какая по вашему, была бы наилучшая реализация динамического массива под C?

lv ★★
() автор топика
Ответ на: комментарий от klalafuda

> malloc/realloc и нефик пудрить мозги.
Оно, конечно да, можно и так. Ну тут напрашивается структура (чтобы хранить количество елементов), функции, чтобы добавляя элементы, отслеживать - хватает ли выделенной памяти. Потом как-то неохота становится под каждый тип данных заводить свой набор структур и функций.. и вот тут мы (ну ладно - я) приходим к макрам. Они конечно страшно смотряться - вот я и спрашиваю - есть ли более красивый вариант.. или не стоит by design?

lv ★★
() автор топика
Ответ на: комментарий от lv

>Ну тут напрашивается структура (чтобы хранить количество елементов), функции, чтобы добавляя элементы, отслеживать - хватает ли выделенной памяти. Потом как-то неохота становится под каждый тип данных заводить свой набор структур и функций.. и вот тут мы (ну ладно - я) приходим к...

Хранению указателей на элемент массива, не?

wfrr ★★☆
()
Ответ на: комментарий от wfrr

> Хранению указателей на элемент массива, не?
Ну я писал - можно и с void * это записать на функциях - так оно, возможно, даже лучше будет.. только нужно, вроде как будет следить за тем, чтобы не передали указатель на локальный объект который разрушится до того, как его значение нам ещё сможет пригодиться. Или выделять все объекты динамически (что тоже не есть хорошо)... вобщем, как мне кажется - тут есть свои недостатки, и их, возможно, даже больше, чем в варианте с макрами.

lv ★★
() автор топика
Ответ на: комментарий от temp

> если развивать мысль -- получится g_array
это к тому, что мне glib глянуть? :) спасибо - посмотрю :)

lv ★★
() автор топика
Ответ на: комментарий от lv

>Или выделять все объекты динамически (что тоже не есть хорошо)...

Если так считать то в си все нехорошо и нужн опереходить на d.

wfrr ★★☆
()
Ответ на: комментарий от wfrr

> Если так считать то в си все нехорошо и нужн опереходить на d.
Да нет - просто, одно дело - выделили здоровый кусок памяти и с ним работаем, другое - постоянно выделяем память для каждого элемента. Второй вариант будет затормаживать процесс, особенно, если элементов много. Вроде так.. :)

lv ★★
() автор топика
Ответ на: комментарий от lv

Для этих целей давно выделяют память блоками.

wfrr ★★☆
()

Ну вот тут http://slil.ru/26295621 собсна рабочий вариант макров с небольшой демонстрационной програмкой. Вроде как всё компилируется и работает - если будут выявлены какие косяки - пишите. :)

lv ★★
() автор топика
Ответ на: комментарий от lv

гы.. в V_GET в первой строке надо (pos)>0 на (pos)>=0 поменять.. ну мож там много чего ещё поменять надо, ну да ладно :)

lv ★★
() автор топика

прально сказали ... malloc/realloc и нефик насиловать мозг ... ты на С пишешь или на чем ... для епли мозгов пиши на яве ...

anonymous
()

и да, макросы оборачивай не в do {} while , а в do {} while(0)

потом, при объялении "вектора" у тебя name##_s, а где то же самое в остальных макросах? или программер дожен телепатически догадаться, что надо будет везде дальше добавлять суффикс?

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

xydo ★★
()

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

alex4
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.