On Sep 10, 11:14 pm, tni <t...@example.invalid> wrote:
> On 2010-09-10 15:31, Alf P. Steinbach /Usenet wrote:
> > * tni, on 10.09.2010 08:31:
> >> On 2010-09-10 5:51, Alf P. Steinbach /Usenet wrote:
> >>> In C++98 you're formally in UB-land when you try that on
> >>> non-POD types such as above.
> >>> For POD types the standard supports it via the discussion
> >>> of layout-compatible types in §9.2, and in particular
> >>> support of reinterpret_cast from first member in struct to
> >>> struct and vice versa in §9.2/17.
> >> Things aren't quite that rosy. You still violate the
> >> aliasing rules and there enough compilers that will happily
> >> generate wrong code.
> > Nah to both.
> I've seen something like that miscompiled by g++ (IIRC
> somewhere around version 4.0).
The issue is not simple, and formally g++ isn't conformant in
this respect (but it has nothing to do with §9.2/17---I've not
verified, but I suspect that g++ does handle that correctly).
But if I understand correctly, the C committee thinks that it is
the standard which is broken, not g++---the standard guarantees
too much.
The exact issue was something like:
union U { int a; double b; }
int f(int* a, double *b)
{
// g++ reorders the following two statements...
int result = *a;
*b = 3.14159;
}
// ...
U u;
u.a = 42;
int i = f(&u.a, &u.b);
Technically, the above code fulfills the requirements of the
standard; you're reading the last element written in the union,
then writing a different element. IIRC, the opinion of the C
committee was that this *should* only be guaranteed to work when
the actual access is through the union type.
This is, of course, more or less irrelevant here, and I suspect
that g++ will recognize layout compatible prefixes, and take
those into account when doing its aliasing analysis. (I suspect
this because the idiom is so prevelant in C. I seem to recall
having seen something similar in the sources of gcc, in fact.)
> >> The only safe thing to do is memcpy or using a union (if
> >> your C++ compiler supports C99 semantics for the union
> >> access, the C++ standard itself doesn't really allow it).
> > Ouch.
> > It's an old C technique. No compiler will foul it up. Don't
> > add needless complexity.
> What's your point?
> This:
> float f;
> int i = *(int*) &f;
> is an old C technique as well with lots of code using it.
> What makes you think it's not a violation of the aliasing
> rules? Given your reference to the first member, you did
> notice that the OP wanted to access the second one as well,
> right?
That's maybe an issue in C++. The wording of the C standard
guarantees that all elements of a common prefix will work. And
I'm not sure, but I seem to recall that it was guaranteed even
if a union wasn't involved.
> (I can see the argument that access to the first member might
> be safe. But the language in the standard isn't really
> explicit that you are not violating the aliasing rules and
> that's always dangerous.)
The first member of a PODS is guaranteed to be at the same
address as the structure itself. That's one guarantee. There
is another one concerning PODS with layout compatible initial
sequences. In C++, this is only guaranteed if the structs are
in a union; in C, I think it is generally guaranteed (but I
don't have access to a C standard here to verify). In practice,
things like:
struct Node
{
int nodeType;
int childCount;
};
struct BinaryOperatorNode
{
int nodeType;
int childCount;
Node* left;
Node* right;
};
and then:
Node* currentNode;
// ...
if (isBinaryNode(currentNode->nodeType)) {
BinaryOperatorNode* binaryNode =
(BinaryOperatorNode*)currentNode;
// ...
}
is a more or less standard technique in C, used (IIRC) in the
gcc compiler itself. I don't think that g++ would break this.
--
James Kanze