int
and const int
are not compatible types (6.7.3p10) so you wouldn't be able to apply the common initial sequence rule (6.5.2.3p6) for storage in a union
; that said, that's not what you're doing anyway, so you must be relying on the lvalue conversion rules (6.3.2.1p2) which allow stripping one layer of type qualification, but only if the lvalue refers to an object of appropriate type.
Note that from 6.2.5p26 and 6.7.2.1p15 we can infer that the two struct
s have the same layout (for the public elements) but it does not follow that what you're doing is legitimate. As discussed at "Private" struct members in C with const, the key is that the optimiser (when operating on user code) will note that the members of struct public
are const
and infer that they cannot be changed anywhere including by (member) functions of the implementation.
However, if you're happy to trust the user to not const-cast this->n
, then they can be trusted to not const-cast this
, so why not give them a pointer to a const
-qualified object? You can even make public
a const
typedef:
typedef const struct initial {
int n;
void *data;
} public;
In addition, it makes sense to reuse the initial
layout at the cost of a few extra characters:
struct private {
struct initial i;
int field;
};
You can now give users &this->i
and as initial
and public
are qualified versions of compatible types you don't even need to cast anything (though you could, by 6.7.2.1p15).