Diagnostic required here, as in a similar case from your earlier
post. Do these diagnostics make no impression on you, not even so
much as to raise a teeny-tiny doubt about the validity of what
you're trying to do?
> return EXIT_SUCCESS;
> }
> </code>
>
>
> If the layout of baz.foo and foo2, as well as baz.bar and bar2, is
> guaranteed to be the same, and both foo2 and bar2 are stand-alone objects
> which weren't defined in a union type, doesn't this guarantee the access to
> the "common initial sequence" whether an object is casted to struct Foo or
> struct Bar?
Let's start by dismissing the layout issue (I think we can do
this). Argument: Suppose struct Foo and struct Bar are declared
identically in modules x.c and y.c, but only in x.c do they appear
in a union. Since corresponding structs in x and y are compatible
(6.2.7p1) they must be arranged identically: An x function can
pass a pointer to an instance of x's struct Foo to a y function,
where the representation must be the same as in y. Therefore the
union membership in x cannot influence the compiler's choice of
how to lay out a struct Foo, because it must end up with the same
layout as is used in union-free y. Layout is not the issue.
I'm no code-generation and optimization expert, but I think the
"special guarantee" is about aliasing, not about representation. In
the absence of a union containing both struct Foo and struct Bar,
the compiler can assume that the elements in instances of the two
are distinct: The bytes in a certain memory area represent the value
of a struct Foo *or* of a struct Bar, not both. (This is just like
other types: Some batch of bytes belongs to an int *or* to a double,
and unless there's a union in the picture they cannot belong to both.)
If you use type-punning to access the bytes via a "foreign" type, the
compiler is not obliged to notice or respect the pun (6.5p7; some
specific puns are permitted, but not all).
The code in your post would be, I think, entirely well-behaved
and well-defined if the third processFoo() call were removed. With
the third call in place, it runs afoul of 6.5.2.2p2, violating a
"shall" in a Constraints clause. If you were to add a cast you'd
avoid the 6.5.2.2p2 issue, but 6.5p7 still operates.
What you're doing is "likely to work" in simple cases and with
compilers that don't optimize aggressively. But remember: Memory
is s-l-o-w compared to CPU's, so compiler writers have a large and
growing incentive to find clever ways to avoid accesses. (I write,
by the way, from experience: More than fifteen years ago a compiler
of my acquaintance optimized a pun not unlike yours, producing code
that caught intermittent and hard-to-reproduce SIGSEGV's; it took
three engineers a week and a half to track down the trouble.)
--
Eric Sosman
eso...@comcast-dot-net.invalid