6

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
  • By the way, the API was just an example. It doesn't need to be exactly the same API. Commented Apr 22, 2009 at 15:37

3 Answers 3

6

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);
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, that sounds not so hard. However, is it possible that I stumble upon issues with padding or something like that?
@frw, you shouldn't because you're using malloc to allocate space for the struct data. Since it's stored in a dictionary there should be one alloc per member. Padding issues only really come about if you're padding them within a contiguous block of memory. You could take that approach although I would avoid it, specifically because of packing reasons ;)
Fine, I'll read a bit about packing and see what I'm going to do. However, using C/Invoke would be the simplest solution. Thanks for now!
1

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.

Comments

0

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.

1 Comment

Unfortunately that's no option for me. Thanks anyway :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.