cunions

# Calculating malloc size of a tagged union (without over-allocating)

Let's say I have the following structure:

``````typedef struct MyObject {
char* tag;
union {
BigObject b;     // imagine this is 5MB
SmallObject s;   // imagine this is 8 bytes
} u;
}
``````

From the standard (copied from this answer):

...The size of a union is sufficient to contain the largest of its data members. Each data member is allocated as if it were the sole member of a struct.

Is there a way to get the exact size to `malloc` for a particular struct? It would be something like `tag*` (8) + padding (?) + [small or big object size] (?). In other words, how can I get what amounts to `MyObject o; sizeof(o)` which takes into account the proper `union`-ed object size?

Solution

• When allocating memory for a structure, you must give enough space for the entire thing, even if you only use the smaller member of a containing union.

If you didn't allocate enough memory and you were to write to the larger member, you would invoke undefined behavior for writing past allocated memory. Even if you only wrote to the smaller member, there's no guarantee you wouldn't have a problem.

For example, if you did this:

``````MyObject *o1, *o2;
o1 = malloc(sizeof(char *) + sizeof(SmallObject));
o2 = malloc(sizeof(char *) + sizeof(SmallObject));
o1->tag = "small";
// assign values in o1.u.s
*o2 = *o1;
``````

The assignment on the last line would trigger undefined behavior because the entire struct would be copied.

The way your struct is currently defined, best to just allocate `sizeof(struct MyObject)` bytes and be done with it.

As an alternative, you could instead have pointers to the containing structs and allocate space for them separately.

``````typedef struct MyObject {
char* tag;
union {
BigObject *b;
SmallObject* s;
} u;
} MyObject;

...
MyObject *o = malloc(sizeof(MyObject));
o->tag = "big";
o->u.b = malloc(sizeof(BigObject));
``````