I have a structure as below
struct things
{
BOOL_T is_copy; /* is false */
handle1 h1;
handle2 h2;
int n;
void * memory;
};
Sometimes I make a copy of objects of things in below structure
struct copy_of_things
{
BOOL_T is_copy; /* is true */
handle1 h1; /* I don't need h2 and n here */
void * memory; /* copied from things object and
things object allocates new memory */
int another_member;
};
Also I have an array of structure in a manager that keeps all the things and copy_of_things structure living in my program(call it struct things *things_array[SIZE_OF_ARRAY];). I can not manage 2 arrays because of design requirements(Arrays are similar to hash). To enable this, I made the type of this array as thing * and changed the type of copy_of_things as below
struct copy_of_things
{
struct things ths;
int another_member;
};
Now I can read is_copy member of my array elements and decide whether to interpret it as things or copy_of_things.
I feel this is not only inefficient in terms of memory but ugly looking.
Solution 2
I also plan to use type of array is struct of type(is_copy) and a union.
struct things {
BOOL_T is_copy;
union {
struct { /* is_copy = false */
handle1 h1;
handle2 h2;
int n;
void * memory;
} t;
struct { /* is_copy = true */
handle1 h1;
void * memory;
int another_member;
} c;
};
But while reviewing I found this design also ugly.
Solution 3 I plan to keep BOOL_T is_copy; as first member of both structure and keep array of type BOOL_T. After reading the content of BOOL_T I can de-reference my pointer to things or copy_of_things. I am not sure if this is a good solution and provides a well defined behaviour (at higher level of optimization) as same address is interpreted as different types.
Question Is there a better solution for my problem that is portable on any platform.
EDIT
Thank you for the answers. So there are two suggested alternatives.
- Use Unions: Downside of the approach is, it requires more memory for copies. In my case the
sizeof copy_of_thingsis significantly smaller thansizeof things. One workaround would be alloc just enough bytes in which actual object can reside. - Use a common struct and make it first member of both
copy_of_thingsandthings. Here I would end up de-referencing same memory location with 2 types (struct common and struct things or struct copy_of_things). I am not sure that strict aliasing rule won't bite me. - One more solution can be keep first member of both structs as
char is_copy; /* \0 if not a copy, non zero otherwiseand access the pointer only aschar *orthings *orcopy_of_things *.
Still open question
I have seen solution 2 used at many places. Is it strict aliasing rule safe? Is there a better solution to my problems as the code would be compiled on a variety of compilers. Size of reverse mapping array is large so I am avoiding to use a union or a solution that increases the size of reverse mapping. Number of things (and copy) are less, so it is okay to add new data member there.