Как динамически создавать и читать структуры в 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 может это сделать, но есть ли отдельная библиотека для этого?
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