Casts on lvalues

H

Heikki Kallasjoki

I think you may be mistaken on that last point.

Are you saying that (with such an extension), this:

union {
unsigned u;
float f;
};
f = 1.0;
printf("0x%x\n", u);

would be allowed? I haven't seen that; gcc warns "unnamed
struct/union that defines no instances". In other words, a
standalone anonymous union is already valid but useless.

At least from C99 onwards, I don't think it's "already valid"; based on
the constraint in C99 6.7p2:

A declaration shall declare at least a declarator (other than the
parameters of a function or the members of a structure or union), a
tag, or the members of an enumeration.

It would therefore be a non-conflicting extension to assign some
compiler-specific meaning on such code. (Though I have not come across
such an extension anywhere either.)
 
I

Ian Collins

Keith said:
James Kuyper said:
On 12/09/2012 01:50 PM, BartC wrote: [...]
union {
S* p;
T* pt;
};

That, on the other hand, would work, and is trivially compatible with
the current C language. Anonymous unions are already allowed as members
in structures (as of C2011), and stand-alone anonymous unions have, I
believe, long been a common extension to C.

I think you may be mistaken on that last point.

Are you saying that (with such an extension), this:

union {
unsigned u;
float f;
};
f = 1.0;
printf("0x%x\n", u);

would be allowed? I haven't seen that; gcc warns "unnamed
struct/union that defines no instances". In other words, a
standalone anonymous union is already valid but useless.

Sun cc is a little less subtle:
warning: useless declaration

What did surprise me is the code appears to be valid C++! I guess you
learn something new every day.
 
J

James Kuyper

James Kuyper said:
On 12/09/2012 01:50 PM, BartC wrote: [...]
union {
S* p;
T* pt;
};

That, on the other hand, would work, and is trivially compatible with
the current C language. Anonymous unions are already allowed as members
in structures (as of C2011), and stand-alone anonymous unions have, I
believe, long been a common extension to C.

I think you may be mistaken on that last point.

Are you saying that (with such an extension), this:

union {
unsigned u;
float f;
};
f = 1.0;
printf("0x%x\n", u);

would be allowed? I haven't seen that; gcc warns "unnamed
struct/union that defines no instances". In other words, a
standalone anonymous union is already valid but useless.

They are permitted and useful in C++; that may be what I was thinking of.
 
J

James Kuyper

At least from C99 onwards, I don't think it's "already valid"; based on
the constraint in C99 6.7p2:

A declaration shall declare at least a declarator (other than the
parameters of a function or the members of a structure or union), a
tag, or the members of an enumeration.

It would therefore be a non-conflicting extension to assign some
compiler-specific meaning on such code. (Though I have not come across
such an extension anywhere either.)

As I said, it's "already allowed as members in structures (as of
C2011)", not C99. See 6.7.2.1p13: "an unnamed member whose type
specifier is a union specifier with no tag is called an anonymous
union.", where "anonymous union" is italicized, indicating that this
sentence serves to define that term.

However, they don't seem to have made a corresponding change to 6.7p2. I
don't see any way to interpret it that's compatible with the anonymous
structure and union members that were added in C2011. That may have been
an oversight - hopefully Larry Jones can comment?
 
H

Heikki Kallasjoki

^^^^^^^^^^^^^
At least from C99 onwards, I don't think it's "already valid"; based on
the constraint in C99 6.7p2:
[..]

As I said, it's "already allowed as members in structures (as of
C2011)", not C99. See 6.7.2.1p13: "an unnamed member whose type

It was, however, the highlighted instance of "already valid" from Keith
Thompson that I was commenting on; the one considering the standalone
case.

(Apologies for the confusion.)
 
J

James Kuyper

the current C language. Anonymous unions are already allowed as members
in structures (as of C2011), and stand-alone anonymous unions have, I
believe, long been a common extension to C.

I think you may be mistaken on that last point.

Are you saying that (with such an extension), this:

union {
unsigned u;
float f;
};
f = 1.0;
printf("0x%x\n", u);

would be allowed? I haven't seen that; gcc warns "unnamed
struct/union that defines no instances". In other words, a
standalone anonymous union is already valid but useless. ^^^^^^^^^^^^^
At least from C99 onwards, I don't think it's "already valid"; based on
the constraint in C99 6.7p2:
[..]

As I said, it's "already allowed as members in structures (as of
C2011)", not C99. See 6.7.2.1p13: "an unnamed member whose type

It was, however, the highlighted instance of "already valid" from Keith
Thompson that I was commenting on; the one considering the standalone
case.

(Apologies for the confusion.)

It was my confusion - your wording was clear enough. I'm not sure how I
managed to misread it that way. I remember looking for, and not finding,
the word 'valid' in the preceding text, so I must not have been fully
awake when I performed that search. Therefore, I keyed in on the only
use of 'already' that I could find (another indication that I wasn't
fully awake).
 
K

Keith Thompson

Heikki Kallasjoki said:
the current C language. Anonymous unions are already allowed as members
in structures (as of C2011), and stand-alone anonymous unions have, I
believe, long been a common extension to C.

I think you may be mistaken on that last point.

Are you saying that (with such an extension), this:

union {
unsigned u;
float f;
};
f = 1.0;
printf("0x%x\n", u);

would be allowed? I haven't seen that; gcc warns "unnamed
struct/union that defines no instances". In other words, a
standalone anonymous union is already valid but useless. ^^^^^^^^^^^^^
At least from C99 onwards, I don't think it's "already valid"; based on
the constraint in C99 6.7p2:
[..]

As I said, it's "already allowed as members in structures (as of
C2011)", not C99. See 6.7.2.1p13: "an unnamed member whose type

It was, however, the highlighted instance of "already valid" from Keith
Thompson that I was commenting on; the one considering the standalone
case.

(Apologies for the confusion.)

Your statement was both sufficiently clear and correct; a standalone
anonymous union is *not* valid in C99 (i.e., I was mistaken).
 
T

Tim Rentsch

Keith Thompson said:
A footnote in the standard (N1370 6.5.2.3p3, footnote 95) says:

If the member used to read the contents of a union object is
not the same as the member last used to store a value in the
object, the appropriate part of the object representation of
the value is reinterpreted as an object representation in the
new type as described in 6.2.6 (a process sometimes called
"type punning"). This might be a trap representation.

I'm not sure why that's stated only in a non-normative footnote.
I suppose the implication is that it's already stated normatively,
but it's not clear to me that it is.

I've explained this before. It's a consequence of the definition
of union types and the normal rules for lvalue conversion. There
isn't anything hard about it for anyone willing to sit down and
trace through the different sections; all it takes is checking
that everything is defined and what the defined semantics are.
Basically, if variable access "works", then doing a type-punning
access on a union member has to "work", because the same semantics
are invoked in the two cases.
 
T

Tim Rentsch

C99 has such texts:

6.2.5p20, union has an overlapping set of member objects
6.7.2.1p14, the value of at most one of the members can be stored in a union object at any time
Annex J.1 the value of a union member other than the last one stored into is unspecified.

I do not feel it safe to use union for type punning.

And you feel that way despite the Standard clearly stating
in plain English that this is how union access /does/ work,
including explaining that it is called 'type punning'?
 
T

Tim Rentsch

Keith Thompson said:
@C3{96}@C3{B6} Tiib said:
C99 has such texts:

6.2.5p20, union has an overlapping set of member objects
6.7.2.1p14, the value of at most one of the members can be stored
in a union object at any time
Annex J.1 the value of a union member other than the last one
stored into is unspecified.

I do not feel it safe to use union for type punning.

Note that C99 doesn't have that footnote, but N1256 does. It was added
by one of Technical Corrigenda 3 -- but N1256 (which incorporates TC3)
still has that clause in Annex J.1. I suspect this is just an
oversight.

N1570 (essentially C2011) changed the wording of the clause in J.1
(which is a list of unspecified behaviors) from:
The value of a union member other than the last one stored into
(6.2.6.1)
to:
The values of bytes that correspond to union members other than the
one last stored into (6.2.6.1).

I can't find the list of C99 DRs (the link I had,
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm>
now points to the list of C2011 DRs), so I don't know which DR
introduced this change.

But the implication is that the committee felt that the existing C99
standard already implied what the footnote says. [snip]

In fact, the footnote was added precisely because someone was
concerned it wasn't obvious (or obvious enough) that C99's
rules produced the same behavior (ie, type punning) for union
access as had been true before C99.
 
T

Tim Rentsch

James Kuyper said:
I'm not talking about all optimizations, just the ones that depend upon
C's anti-aliasing guarantees. Consider the following function:

void func(int n, float array[static n], long *l)
{
for(int i=0; i<n; i++)
array = *l;
*l = n;
}

An implementation is permitted, because of 6.5p7, to compile that
function as if it had been written:
void func(int n, float array[static n], long *l)
{
long temp = *l;
for(int i=0; i<n; i++)
array = temp;
*l = n;
}

The optimized version has exactly the same behavior as the original, so
long as 6.5p7 is not violated. If C were changed to allow a long integer
to be equivalenced with a element of a float array, the value of *l
might change during the loop.


(Seems like it might just be copied to itself? In this example).


I think you're assuming that sizeof(long)==sizeof(float), which is
commonplace, but not required. However, even on systems where that is
true, the result is not a simple copy. The conversion to float will
produce a bit pattern that's pretty unlikely to be the same as the
original (unless the original represents 0).
I can't see that the problems are going to be that different from the ones
you might get when using pointers. (And the solutions might be similar.)

In C, such code using pointer casts violates 6.5p7, and therefore has
undefined behavior, so the solution is simply not to write such code.
Because even without equivalencing, 'l' might anyway point into the array,
via a cast.

Not with defined behavior.
If this was part of the language, at least the aliasing would be done in an
overt manner, not hidden away in a pointer cast, in an operation done at
runtime so you don't know at any time what is aliasing what.

As I said, the C language does provide a way to explicitly alias objects
of two different types, and the optimizations I've described above are
therefore prohibited when they occur within the scope of a union
declaration that connects the relevant types [snip unimportant exception].


I think you'd get some disagreement on this last point. It
is not enough that the types in question just co-reside in a
visible union type. If that were true there would be no reason
for the "special rule" about struct's and accessing their
common prefix.
 
T

Tim Rentsch

James Kuyper said:
As I said, it's "already allowed as members in structures (as of
C2011)", not C99. See 6.7.2.1p13: "an unnamed member whose type
specifier is a union specifier with no tag is called an anonymous
union.", where "anonymous union" is italicized, indicating that this
sentence serves to define that term.

However, they don't seem to have made a corresponding change to 6.7p2. I
don't see any way to interpret it that's compatible with the anonymous
structure and union members that were added in C2011. That may have been
an oversight - hopefully Larry Jones can comment?

6.7p2 applies to declarations. The elements defining the contents
of a struct (or union) type, including anonymous structs (or unions)
are struct-declarations, not declarations. 6.7p2 doesn't apply.
 
L

lawrence.jones

Keith Thompson said:
Thanks!

(Small annoying quibble: Those are C90 DRs, not C89 DRs; they refer to
the C90 section numbers.)

Oops, right you are! DRs are an ISO thing, so they naturally refer to
the ISO standard rather than the ANSI one.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

function casts 27
Casts 81
Lexical Analysis on C++ 1
lvalues and rvalues 127
Union and pointer casts? 13
Pointer casts for OOP 2
Function is not worked in C 2
Fun with casts 1

Members online

Forum statistics

Threads
474,077
Messages
2,570,567
Members
47,203
Latest member
EmmaSwank1

Latest Threads

Top