I have a struct X which inherits from struct Base. However, in my current setup, due to alignment, size of X is 24B:
typedef struct {
double_t a;
int8_t b;
} Base;
typedef struct {
Base base;
int8_t c;
} X;
In order to save the memory, I'd like to unwind the Base struct, so I created struct Y which contains fields from Base (in the same order, always at the beginning of the struct), so the size of the struct is 16B:
typedef struct {
double_t base_a;
int8_t base_b;
int8_t c;
} Y;
Then I'm going to use instance of struct Y in a method which expects a pointer to Base struct:
void print_base(Base* b)
{
printf("%f %d\n", b->a, b->b);
}
// ...
Y data;
print_base((Base*)&data);
Does the code above violates the strict aliasing rule, and causes undefined behavior?
First, Base
and Y
are not compatible types as defined by the standard 6.2.7, all members must match.
To access an Y
through a Base*
without creating a strict aliasing violation, Y
needs to be "an aggregate type" (it is) that contains a Base
type among its members. It does not.
So it is a strict aliasing violation and furthermore, since Y
and Base
are not compatible, they may have different memory layouts. Which is kind of the whole point, you made them different types for that very reason :)
What you can do in situations like this, is to use unions with struct members that share a common initial sequence, which is a special allowed case. Example of valid code from C11 6.5.2.3:
union {
struct {
int alltypes;
} n;
struct {
int type;
int intnode;
} ni;
struct {
int type;
double doublenode;
} nf;
} u;
u.nf.type = 1;
u.nf.doublenode = 3.14;
/* ... */
if (u.n.alltypes == 1)
if (sin(u.nf.doublenode) == 0.0)