A number of answers for the Stack Overflow question Getting the IEEE Single-precision bits for a float suggest using a union
structure for type punning (e.g.: turning the bits of a float
into a uint32_t
):
union {
float f;
uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;
However, the value of the uint32_t
member of the union appears to be unspecified according to the C99 standard (at least draft n1124), where section 6.2.6.1.7 states:
When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.
At least one footnote of the C11 n1570 draft seems to imply that this is no longer the case (see footnote 95 in 6.5.2.3):
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.
However, the text to section 6.2.6.1.7 is the same in the C99 draft as in the C11 draft.
Is this behavior actually unspecified under C99? Has it become specified in C11? I realize that most compilers seem to support this, but it would be nice to know if it's specified in the standard, or just a very common extension.
The behavior of type punning with union changed from C89 to C99. The behavior in C99 is the same as C11.
As Wug noted in his answer, type punning is allowed in C99 / C11. An unspecified value that could be a trap is read when the union members are of different size.
The footnote was added in C99 after Clive D.W. Feather Defect Report #257:
The wording of Clive D.W. Feather was accepted for a Technical Corrigendum in the answer by the C Committee for Defect Report #283.
This has always been "iffy". As others have noted a footnote was added to C99 via a Technical Corregendum. It reads as follows:
However, footnotes are specified in the Foreword as non-normative:
That is, the footnotes cannot proscribe behaviour; they should only clarify the existing text. It's an unpopular opinion, but the footnote quoted above actually fails in this regard - there is no such behaviour proscribed in the normative text. Indeed, there are parts such as 6.7.2.1:
In conjunction with 6.5.2.3 (regarding accessing union members with the "." operator):
I.e. if the value of only one member can be stored, the value of another member is non-existent. This strongly implies that type punning via a union should not be possible; the member access yields a non-existent value. The same text still exists in the C11 document.
However, it's clear that the purpose of adding the footnote was to allow for type-punning; it's just that the committee seemingly broke the rules on footnotes not containing normative text. To accept the footnote, you really have to disregard the section that says footnotes aren't normative, or otherwise try to figure out how to interpret the normative text in such a way that supports the conclusion of the footnote (which I have tried, and failed, to do).
The section you quote:
... has to be read carefully, though. "The bytes of the object representation that do not correspond to that member" is referring to bytes beyond the size of the member, which isn't itself an issue for type punning (except that you cannot assume writing to a union member will leave the "extra" part of any larger member untouched).
The original C99 specification left this unspecified.
One of the technical corrigenda to C99 (TR2, I think) added footnote 82 to correct this oversight:
That footnote is retained in the C11 standard (it's footnote 95 in C11).
No, you're fine.
This applies to data blocks of different sizes. I.e, if you have:
and you assign something to f, it would change the lower 4 bytes of d, but the upper 4 bytes would be in an indeterminate state.
Unions exist primarily for type punning.