Как динамически создавать и читать структуры в C?



Как я могу сделать что-то подобное (просто пример):



any_struct *my_struct = create_struct();
add_struct_member(my_struct, "a", int_member);
add_struct_member(my_struct, "b", float_member);


Чтобы я мог загрузить и использовать экземпляр struct "извне" (по адресу addressOfMyStruct) с данной структурой здесь?



any_struct_instance *instance = instance(my_struct, addressOfMyStruct);
int a = instance_get_member(instance, "a");
float b = instance_get_member(instance, "b");


Я также хотел бы иметь возможность динамически создавать экземпляры struct таким образом.



Надеюсь, вам ясно, что я хочу сделать. Я знаю, что C / Invoke может это сделать, но есть ли отдельная библиотека для этого?
544   3  

3 ответов:

На самом деле демонстрация кода, чтобы сделать эту работу в C, немного слишком сложна для so-поста. Но объяснение основной концепции выполнимо.

На самом деле вы создаете здесь шаблонную систему пакетов свойств. Единственное, что вам понадобится, чтобы это продолжалось, - это некоторая ассимилятивная структура, такая как хэш-таблица. Я бы сказал пойти с std:: map, но вы упомянули, что это было единственным решением C. Для обсуждения я просто предположу, что у вас есть какая-то доступная хэш-таблица.

В "create_struct" звонок нужно будет возвращать структуру, которая содержит указатель на хэш-таблицу, что делает const char*, по существу, значение size_t. Эта карта определяет, что вам нужно для того, чтобы создать новый экземпляр структуры.

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

Реализация instance_get_member будет просто выполнять поиск в карте по имени. Хотя подпись и шаблон использования должны будут измениться. C не поддерживает шаблоны и должен выбрать общий тип возвращаемого значения, который может представлять все данные. В этом случае вам нужно будет выбрать void*, так как именно так будет храниться память.

void* instance_get_member(any_struct_instance* inst, const char* name);

Вы можете сделать это немного лучше, добавив макрос envil для имитации шаблонов

#define instance_get_member2(inst, name, type) \
  *((type*)instance_get_member((inst),(name)))
...
int i = instance_get_member2(pInst,"a", int);

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

typedef struct {
    fieldType type;
    char      name[NAMEMAX];
    /* anything else */
} meta_struct_field;
typedef struct {
    unsigned          num_fields;
    meta_struct_field *fields;
    /* anything else */
} meta_struct;

Затем create_struct() выделяет память для meta_struct и инициализирует ее до 0, а add_struct_member() выполняет alloc()/realloc() о my_struct.fields и приращениях my_struct.num_fields. Остальное следует в том же духе.

Вы также захотите, чтобы union в meta_struct_field содержал фактические значения в экземплярах.

Кое-что из этого я сделал давным-давно.

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

Comments

    Ничего не найдено.