I had a similar question a while ago , and I think I can answer your question.
Yes, struct a and struct b are not compatible types, and pointers to them are also incompatible.
Yes, what you do is illegal even from the outdated point of view of the C89 standard. However, it may be interesting to note that if you change the order of the elements in struct a and struct b , you can access the int i struct c instance (but not access its next pointer in any way, i.e. bar->i = 9; instead of bar->next->i = 9; ), but only from the point of view of C89.
But even if you change the order of the elements in two struct s, what you do will still be illegal in terms of the C99 and C11 standards (as interpreted by the commit). On C99, part of the standard you specified was changed to:
To simplify the use of unions, there is one special guarantee: if the union contains several structures that have a common initial sequence (see below), and if the union object currently contains one of these structures, it is allowed to check the common initial part of any of them anywhere, so that the declaration of the completed join type is visible .
The last phrase is a bit ambiguous, since you can interpret the “visible” in several ways, but according to the commit, this means that the check must be performed on the object of the type of union in question.
So, in your case, the correct way to handle this would be as follows:
struct a { int i; struct a *next; }; struct b { int i; struct b *next; }; union un { struct aa; struct bb; }; struct c { int x, x2, x3; union un u; }; void foo(union un *bar) { bar.b->next->i = 9; return; } foo(&c.u);
This is good and interesting from the point of view of a lawyer language, but in fact, if you do not apply different packaging settings to them, a struct with the same initial sequence will have the same layout (in 99.9% of cases). In fact, they must have the same layout even in the initial setup, since pointers to struct a and struct b must be the same size. That way, if your compiler doesn't get nasty when you break a strict alias, you can more or less safely display between them or use them in union the way you use them now.
EDIT : as @underscore_d noted in the comments on this answer, since the corresponding sentences in the C ++ standards do not have the line “wherever declared a completed type of union visible” in their respective parts, it is possible that the C ++ standard has such The same position on this issue as the standard C89.