Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Re: Aliasing in C99

Thread Tools

Re: Aliasing in C99

James Kuyper
Posts: n/a
On 05/31/2012 10:01 AM, David Brown wrote:
> I am trying to figure out how to get aliasing to work correctly according
> to the C99 rules. For example, converting between a float and its binary
> representation.
> float negPCast(float x) {
> uint32_t u = *((uint32_t *) &x);
> u ^= 0x80000000u;
> return *((float *) &u);
> }
> In the absence of type-based aliasing, this will negate a float using
> just a simple xor operation (ignore any issues with endianness, int
> sizes, NaNs, etc., since this is just an example).
> The pointer typecasting here will break strict aliasing rules, and is
> therefore not valid C99. (I'm guessing that in this case, most compilers
> will generate code that works as desired - but I'm looking for strictly
> conforming methods.)
> It is possible to re-implement it using type-punning unions:
> float negUnion(float x) {
> union { float f; uint32_t u; } uf;
> uf.f = x;
> uf.u ^= 0x80000000;
> return uf.f;
> }
> This doesn't use pointer typecasting, but I believe type-punning unions
> are undefined in C but implemented "properly" in most compilers.

The C99 standard explicitly clarifies (though only in a non-normative
footnote) that reading the value of a member different from the one last
written to results in reinterpretation of the bytes making up that
object according to the new type. In other words, it matches exactly
what most C compilers have done all along. As long as you're willing to
make a host of unportable assumptions about the representation of
'float' and 'uint32_t', your code should work.

> It is also possible to use pointers to unions in casts:
> float negUnionPCast(float x) {
> typedef union { float f; uint32_t u; } UF;
> uint32_t u = ((UF*) &x)->u;
> u ^= 0x80000000u;
> return ((UF*) &u)->f;
> }
> I /think/ pointer casts like this are not subject to strict aliasing
> rules, but I don't know if the union usage is valid.

If you had an actual union object, conversions of pointers to it into
pointers to the member types would be unproblematic. However, doing it
this way could be a problem. If, for instance, float has an alignment
requirement of 2, while uint32_t has an alignment requirement of 4, then
UF will also have an alignment requirement of 4. In that case &x might
not have the right alignment to allow conversion to UF*.

A union is allowed to have unnamed padding bytes. For instance, on a
64-bit machine, it might speed things up to pad this union to 64 bits,
allowing it to be accessed using 64-bit operations. "When a value is
stored in an object of structure or union type, including in a member
object, the bytes of the object representation that correspond to any
padding bytes take unspecified values." ( This will be
problematic since *(UF*)&x is not an actual union object containing
padding bytes that you have permission to set.
James Kuyper
Reply With Quote

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Aliasing in C99 Tim Rentsch C Programming 2 06-01-2012 04:07 PM
Re: Aliasing in C99 Eric Sosman C Programming 3 05-31-2012 09:21 PM
Re: Aliasing in C99 Xavier Roche C Programming 1 05-31-2012 07:10 PM
C99, strict aliasing Mike C Programming 5 07-21-2010 06:47 AM
C99 complex numbers and aliasing Glen Low C Programming 5 08-20-2004 10:13 PM