C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Unions up in arms!

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Glen Low
Guest





PostPosted: Fri Sep 10, 2004 3:13 pm    Post subject: Unions up in arms! Reply with quote




Color me stupid, but after months of staring I still can't grok this
clause in the Standard 3.10/15:

----

If a program attempts to access the stored value of an object through
an lvalue of other than one of the following types the behavior is
undefined:

an aggregate or union type that includes one of the aforementioned
types among its members (including, recursively, a member of a
subaggregate or contained union),

----

Suppose

int j;
union u { int i; float f; };

Then which of the following is illegal, if any, and why? (Putting
aside, if possible, the legality of the popular type-punning practice
of putting x into a union and getting back y.)

A.

j = 12;
int k = ((u&) j).i;

B.

j = 12;
u v = (u&) j;

C.

u v = {12};
float g = v.f;

D.

j = 12;
float g = ((u&) j).f;

And finally, what does "including, recursively, a member of a
subaggregate or contained union" mean?

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Back to top
Bob Hairgrove
Guest





PostPosted: Sat Sep 11, 2004 3:30 pm    Post subject: Re: Unions up in arms! Reply with quote




On Fri, 10 Sep 2004 15:13:17 +0000 (UTC), [email]glenlow (AT) pixelglow (DOT) com[/email] (Glen
Low) wrote:

Quote:

Color me stupid, but after months of staring I still can't grok this
clause in the Standard 3.10/15:

----

If a program attempts to access the stored value of an object through
an lvalue of other than one of the following types the behavior is
undefined:

an aggregate or union type that includes one of the aforementioned
types among its members (including, recursively, a member of a
subaggregate or contained union),

----

Suppose

int j;
union u { int i; float f; };

Then which of the following is illegal, if any, and why? (Putting
aside, if possible, the legality of the popular type-punning practice
of putting x into a union and getting back y.)

A.

j = 12;
int k = ((u&) j).i;

B.

j = 12;
u v = (u&) j;

C.

u v = {12};
float g = v.f;

D.

j = 12;
float g = ((u&) j).f;

Aren't you making a fairly big assumption?
What if sizeof(int) != sizeof(float)?

Quote:
And finally, what does "including, recursively, a member of a
subaggregate or contained union" mean?

Just what it says.

--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]



Back to top
Peter Koch Larsen
Guest





PostPosted: Mon Sep 13, 2004 3:37 pm    Post subject: Re: Unions up in arms! Reply with quote





"Glen Low" <glenlow (AT) pixelglow (DOT) com> skrev i en meddelelse
news:9215d7ac.0409081832.4ab088d6 (AT) posting (DOT) google.com...
Quote:

Color me stupid, but after months of staring I still can't grok this
clause in the Standard 3.10/15:

----

If a program attempts to access the stored value of an object through
an lvalue of other than one of the following types the behavior is
undefined:

an aggregate or union type that includes one of the aforementioned
types among its members (including, recursively, a member of a
subaggregate or contained union),

----

Suppose

int j;
union u { int i; float f; };

Then which of the following is illegal, if any, and why? (Putting
aside, if possible, the legality of the popular type-punning practice
of putting x into a union and getting back y.)

None of them are illegal, but they all give undefined behaviour. In effect,
this means that if it works in your environment it is okay as your code is
nonportable anyway (relying on int and float having same size and alignment
requirements).
Quote:

A.

j = 12;
int k = ((u&) j).i;

B.

j = 12;
u v = (u&) j;

C.

u v = {12};
float g = v.f;

D.

j = 12;
float g = ((u&) j).f;

And finally, what does "including, recursively, a member of a
subaggregate or contained union" mean?

Sorry - no idea... are you quoting the standard?


[snip]

/Peter


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


Back to top
Glen Low
Guest





PostPosted: Mon Sep 13, 2004 3:37 pm    Post subject: Re: Unions up in arms! Reply with quote


Quote:
Aren't you making a fairly big assumption?
What if sizeof(int) != sizeof(float)?

Let's assume that it is so.

Quote:
And finally, what does "including, recursively, a member of a
subaggregate or contained union" mean?

Well, interpretation A was that:

an object of type int can be accessed by a lvalue of type union { int
i; float f }; and also an lvalue of type union { union { int i; float
f}; float g; };

But that doesn't make sense, since if the lvalue is constrained to be
of struct type instead, you could possibly access an undefined value
e.g. the float value.

Interpretation B is that

an object of type int can be accessed by a lvalue of type union { int
i; float f; }.i or union {int i; float f; }.f etc.

This hinges on the phrase "through an lvalue", since the actual lvalue
is no longer of union (or struct) type. I see a lot of gcc users
advocating this, e.g. Mark Mitchell of Codesourcery who contributed
the type-based alias analysis code to gcc.

Interpretation C is that

an object of type union { int i; float f; }; or union { union { int i;
float f; } float g; }; can be accessed by a lvalue of type int or
float

This seems the safest, but relies on twisting the order of the
language in the Standard.

So which is it?

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Mon Sep 13, 2004 10:47 pm    Post subject: Re: Unions up in arms! Reply with quote


[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) wrote in message
news:<9215d7ac.0409081832.4ab088d6 (AT) posting (DOT) google.com>...

Quote:
Color me stupid, but after months of staring I still can't grok this
clause in the Standard 3.10/15:

----

If a program attempts to access the stored value of an object through
an lvalue of other than one of the following types the behavior is
undefined:

an aggregate or union type that includes one of the aforementioned
types among its members (including, recursively, a member of a
subaggregate or contained union),

----

The wording is a bit difficult, to put it mildly. I think that the key
is in the (non-normative) footnote. These restrictions are basicly
there to tell compiler writers what they can exclude (or rather what
they cannot exclude) as possible aliases. Thus, if I have

strut S { int i ; float f ; } ;
float ff ;

S* ps ;
float* pf ;

The compiler must assume that *pf is also accessible via ps.

For the rest, there are a lot of other rules which have to be taken into
account. Thus, for example, *(float*)ps is definitly not a legal
access, despite the text you quote.

Quote:
Suppose

int j;
union u { int i; float f; };

Then which of the following is illegal, if any, and why? (Putting
aside, if possible, the legality of the popular type-punning practice
of putting x into a union and getting back y.)

But you can't put it aside. The standard clearly says that the only
member of a union that can be accessed is the last one written.

Quote:
A.

j = 12;
int k = ((u&) j).i;

This is a reinterpret_cast. According to §5.2.10/7, "Except that
converting an rvalue of type 'pointer to T1' to the type 'pointer to
T2' (where T1 and T2 are object types and where the alignement
requirements of T2 are no stricter than those of T1) and back to its
original type yields the original pointer value, the result of such a
pointer conversion is unspecified." So there results here are
unspecified.

Note that even if you converted back to the original type, if float
required stricter alignment (or if the compiler imposed stricter
alignment on unions than on its constituant members), the results would
be unspecified.

Quote:
B.

j = 12;
u v = (u&) j;

Unspecified, see above.

Quote:
C.

u v = {12};
float g = v.f;

The union was initialized with an int. You access the float field.
Undefined behavior. On machines using IEEE, this can cause a trapping
NaN. On machines where floats are larger than ints, who knows what may
happen. In this case, it doesn't even work in practice.

Quote:
D.

j = 12;
float g = ((u&) j).f;

You're using an unspecified pointer to access a field in a union that
doesn't exist. What do you expect to happen.

Quote:
And finally, what does "including, recursively, a member of a
subaggregate or contained union" mean?

It means that if you have a float*, and a U*, for some union or
aggregate, if that union or aggregate contains a float, directly, or
indirectly, as a member of one of its members, then the compiler must
consider that the the two pointers may possibly be aliases for the same
data, i.e. if there is a write through one of the pointers, the compiler
must reread any value read through the other, since this write may have
modified the value.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


Back to top
Glen Low
Guest





PostPosted: Wed Sep 15, 2004 2:34 pm    Post subject: Re: Unions up in arms! Reply with quote


Quote:
The wording is a bit difficult, to put it mildly. I think that the k
ey
is in the (non-normative) footnote. These restrictions are basicly
there to tell compiler writers what they can exclude (or rather what
they cannot exclude) as possible aliases. Thus, if I have

strut S { int i ; float f ; } ;
float ff ;

S* ps ;
float* pf ;

The compiler must assume that *pf is also accessible via ps.

Hewing close to the language of the Standard, if I store into *pf, the
compiler must assume that a read from *ps would be affected. The
question is, are the following reads also affected: ps->i, ps->f ?
Note that *ps has an lvalue of union type and so the above analysis is
correct, but how about ps->f which has an lvalue of float type? Does
"through an lvalue" mean "an lvalue expression of this exact type" or
"an lvalue expression that contains this type in it e.g. as part of a
member access"?

For the sake of argument, let's assume that sizeof (int) == sizeof
(float) and the data in question is a valid sequence of bits for
either int or float.

Cheers,

Glen Low, Pixelglow Software
www.pixelglow.com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


Back to top
llewelly
Guest





PostPosted: Wed Sep 15, 2004 8:19 pm    Post subject: Re: Unions up in arms! Reply with quote


[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) writes:

Quote:
Aren't you making a fairly big assumption?
What if sizeof(int) != sizeof(float)?

Let's assume that it is so.

And finally, what does "including, recursively, a member of a
subaggregate or contained union" mean?

Well, interpretation A was that:

an object of type int can be accessed by a lvalue of type union { int
i; float f }; and also an lvalue of type union { union { int i; float
f}; float g; };

But that doesn't make sense, since if the lvalue is constrained to be
of struct type instead, you could possibly access an undefined value
e.g. the float value.

Interpretation B is that

an object of type int can be accessed by a lvalue of type union { int
i; float f; }.i or union {int i; float f; }.f etc.

This hinges on the phrase "through an lvalue", since the actual lvalue
is no longer of union (or struct) type. I see a lot of gcc users
advocating this, e.g. Mark Mitchell of Codesourcery who contributed
the type-based alias analysis code to gcc.
[snip]


I think if asked him whether or not it was conforming, he would tell
you 'no'.

Wherever I've seen him 'advocating' that construct, it is to replace
an older form of non-standard type punning which gcc no longer
supports, with a different form of non-standard type punning
which gcc still supports; it was always clear from context that
such constructs were not conforming.

IOWs, when compiled with gcc, it will do what experienced gcc users
expect, but it is not conforming.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Fri Sep 17, 2004 3:29 pm    Post subject: Re: Unions up in arms! Reply with quote


[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) wrote in message
news:<9215d7ac.0409140039.727afd2f (AT) posting (DOT) google.com>...

Quote:
The wording is a bit difficult, to put it mildly. I think that the
key is in the (non-normative) footnote. These restrictions are
basicly there to tell compiler writers what they can exclude (or
rather what they cannot exclude) as possible aliases. Thus, if I
have

strut S { int i ; float f ; } ;
float ff ;

S* ps ;
float* pf ;

The compiler must assume that *pf is also accessible via ps.

Hewing close to the language of the Standard, if I store into *pf, the
compiler must assume that a read from *ps would be affected.

Correct.

Quote:
The question is, are the following reads also affected: ps->i, ps->f ?

Good question. ps->f is definitly affected. Formally, I don't think
that the compiler is obliged to take into account ps->i -- reading from
ps->i is undefined behavior if you've written to ps->f, and if *pf
wasn't an alias for ps->f, ps->i shouldn't change.

In practice, I would consider it a poor compiler which didn't support
this. Correct or not, I think it is a common idiom. And although you
do loose an optimization possibility, you only loose it in the presence
of a union, which shouldn't be that frequent. (FWIW: at least one early
C compiler I used, Microsoft C 1.0, didn't support it -- writing into
one field of a union, and reading from another often didn't work.)

Quote:
Note that *ps has an lvalue of union type and so the above analysis is
correct, but how about ps->f which has an lvalue of float type? Does
"through an lvalue" mean "an lvalue expression of this exact type" or
"an lvalue expression that contains this type in it e.g. as part of a
member access"?

For the sake of argument, let's assume that sizeof (int) == sizeof
(float) and the data in question is a valid sequence of bits for
either int or float.

Both of which are irrelevant with regards to the current discussion.
The standard says that reading from any element other than the last one
written is undefined behavior. It doesn't say why, and the compiler is
free to assume that your code doesn't do it.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.