Как динамически создавать и читать структуры в C? - PullRequest
6 голосов
/ 22 апреля 2009

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

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

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

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

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

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

Ответы [ 3 ]

6 голосов
/ 22 апреля 2009

Фактически демонстрация кода для этой работы на C слишком сложна для SO сообщения. Но объяснение основной концепции выполнимо.

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

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

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

Реализация 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);
1 голос
/ 22 апреля 2009

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

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 содержал фактические значения в экземплярах.

0 голосов
/ 22 апреля 2009

Я сделал это давным-давно.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...