I have a structure named container
.
This structure has a pointer of type void named obj_mem
, which will point to some allocated memory.
As this memory has to be able to hold different structure, I keep track of the adress and the type of each element it contains(adress_obj
, type_obj
) for access and casting.
The last property my container
struct is that it has a self reference child
.
So at running time, the user can create children of a container and add object to them.
typedef enum tob{ //type of object
obj1, obj2, obj3, obj4 ...
}t_tob;
typedef struct obj1{
//declare some stuff
}t_obj1;
typedef struct obj2{
//declare some stuff
}t_obj2;
typedef struct obj3{
//declare some stuff
}t_obj3;
typedef struct obj4{
//declare some stuff
}t_obj4;
typedef struct container{
int name_size;
char* name;
int nmbr_obj;
t_tob* type_obj;
char* adress_obj;
void* mem_obj;
int nmbr_child;
struct container* child;
}t_container;
Then I have a function which process the whole data:
It process the object in the obj_mem
of a container.
Then iterate through his children and process their object.
Then iterate through the children of his children and process their
object
ect ... Until the end of the tree.
The problem:
I'm pretty new to programming and I'm not sure it's the right way to do this.
This code will lead to a lot of malloc call, so the memory won't be contiguous, is this a problem ?
Is there any more elegant way of doing this dynamic type of things ?
Do you have any books who could help me learning more on this kind of memory architecture ?
I'm sorry if this post can look a bit blurry but this is how I feel right now.
Thanks for thelp.
the memory won't be contiguous, is this a problem ?
It isn't a problem, but it will hurt performance.
Using better memory locality (continuous memory rather than fragmented memory) helps the CPU utilize it's cache and minimizes cache misses, which can be a very big thing where performance is concerned.
But this isn't really the most important part. You can always optimize this a little later. The most important part is that the data structure actually does what it needs to do.
Is there any more elegant way of doing this dynamic type of things ?
Probably, but I'm not sure what you want to do, so I can't help you.
Normally when writing a dynamic type system, the type of an object is part of the object, i.e.:
struct my_object_s {
unsigned int type;
/* common type data*/
struct vtable_s * vtable;
};
struct my_string_s {
struct my_object_s header;
size_t len;
char str[];
}
This allows an object to be independent from it's container.
Do you have any books who could help me learning more on this kind of memory architecture ?
I read most of what I know on the internet (I do have a few books, but not many of them go into hardware architecture).
You can find far more comprehensive information about Object Oriented Programming with C here. The author has done extensive work explaining the concepts and these same ideas are often used (in part or in whole) when authoring dynamic types.
For example, by having a virtual function table, casting can be avoided entirely.
On the other hand, it's common to use a switch statement when you have a limited set of types.
enum my_type_enum {
/** A simple flag object object (`my_object_s`) for NULL. */
MY_NULL,
/** A simple flag object (`my_object_s`) for OK. */
MY_OK,
/** A simple flag object (`my_err_s`) that indicates an error. */
MY_ERR,
/** A Number object object (`my_number_s`). */
MY_NUMBER,
/** A String object (`my_string_s`). */
MY_STRING,
/** An Array object object (`my_array_s`). */
MY_ARRAY,
};
typedef struct { enum my_type_enum type; } my_object_s;
typedef struct {
my_object_s header;
size_t len;
char str[];
} my_string_s;
void example_usage(my_object_s *obj) {
switch (obj->type) {
case MY_STRING:
printf("String: %s", ((my_string_s *)obj)->str);
break;
default:
printf("whatever...");
}
}
Notice that by having my_object_s
as the header for each one of the types, you can safely access the header data as if any pointer to an object was a my_object_s *
and this way you can discern it's underlying type.