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);