I have a series of structs that all have some relatively verbose initialization logic and am trying to refactor that out into a helper function so I don't have to keep writing it over and over. Here's a condensed version:
struct base
{
const int *i;
}
struct child1
{
struct base b;
int j;
}
struct child2
{
struct base b;
int k;
}
void *alloc_base_holder(const int *i, size_t size)
{
struct base b = { i };
void *anon = malloc(size);
// error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
return memcpy(anon, &b, size);
}
struct child1 *c1_alloc(const int *i)
{
return (struct child1 *)alloc_base_holder(i, sizeof(struct child1));
}
struct child2 *c2_alloc(const int *i)
{
return (struct child2 *)alloc_base_holder(i, sizeof(struct child2));
}
I'm trying to dynamically allocate and initialize the memory given the size of the struct and not the type, but I'm not sure how to do that.
My first thought was to initialize the base
part that is common to all of the child
types, and then just memcpy
that into a void
pointer that had been allocated to the correct size
, but that's giving the error:
error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
I also had the idea to just manually set the memory of the void
pointer (anon
), but if that's possible, I haven't come up with the right search terms to find it.
Is this possible to do and can somebody point me in the right direction?
Edit: I'm using gcc with C99 by the way.
Reason of the warning are explained in the other answer.
I suggest always accessing the object via it's final type (struct child1
or struct child2
). Otherwise one may easily trigger UB due to strict aliasing rules.
Therefore it's better to have init_base_holder()
rather than alloc_base_holder
.
void init_base_holder(struct base *b, const int *i)
{
b->i = i;
}
struct child1 *c1_alloc(const int *i)
{
struct child1 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}
struct child2 *c2_alloc(const int *i)
{
struct child2 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}