问题
How can I do something like that (just an example):
any_struct *my_struct = create_struct();
add_struct_member(my_struct, "a", int_member);
add_struct_member(my_struct, "b", float_member);
So that I could load and use a struct instance "from the outside" (at the address addressOfMyStruct) with the given structure here?
any_struct_instance *instance = instance(my_struct, addressOfMyStruct);
int a = instance_get_member(instance, "a");
float b = instance_get_member(instance, "b");
I would also like to be able to create struct instances dynamically this way.
I hope it's clear what I want to do. I know that C/Invoke is able to do it, but is there a separate library to do that?
回答1:
Actually demonstrating the code to make this work in C is a bit too involved for an SO post. But explaining the basic concept is doable.
What you're really creating here is a templated property bag system. The one thing you'll need a lot of to keep this going is some assiociative structure like a hash table. I'd say go with std::map but you mentioned this was a C only solution. For the sake of discussion I'm just going to assume you have some sort of hashtable available.
The "create_struct" call will need to return a structure which contains a pointer to a hashtable which makes const char* to essentially a size_t. This map defines what you need in order to create a new instance of the struct.
The "insance" method will essentially create a new hashtable with equal number of members as the template hashtable. Lets throw lazy evualation out the window for a second and assume you create all members up front. The method will need to loop over the template hashtable adding a member for every entry and malloc'ing a memory chunk of the specified size.
The implementation of instance_get_member will simply do a lookup in the map by name. The signature though and usage pattern will need to change though. C does not support templates and must chose a common return type that can represent all data. In this case you'll need to chose void* since that's how the memory will need to be stored.
void* instance_get_member(any_struct_instance* inst, const char* name);
You can make this a bit better by adding an envil macro to simulate templates
#define instance_get_member2(inst, name, type) \
*((type*)instance_get_member((inst),(name)))
...
int i = instance_get_member2(pInst,"a", int);
回答2:
You've gone so far defining the problem that all that's left is a bit of (slightly tricky in some parts) implementation. You just need to keep track of the information:
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;
Then create_struct() allocates memory for meta_struct and initialized it to 0, and add_struct_member() does an alloc()/realloc() on my_struct.fields and increments my_struct.num_fields. The rest follows in the same vein.
You'll also want a union in meta_struct_field to hold actual values in instances.
回答3:
I did some of this a long time ago.
The way I did it was to generate code containing the struct definition, plus all routines for accessing it and then compile and link it into a DLL "on the fly", then load that DLL dynamically.
来源:https://stackoverflow.com/questions/777689/how-to-dynamically-create-and-read-structs-in-c