Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #21619

Re: Aliasing in C99

Date 2012-06-01 09:52 +0200
From David Brown <david@westcontrol.removethisbit.com>
Newsgroups comp.lang.c
Subject Re: Aliasing in C99
References <w5OdnYaSNZID5FrSnZ2dnUVZ8kqdnZ2d@lyse.net> <kfnk3zsyso9.fsf@x-alumni2.alumni.caltech.edu> <kZmdndBWeqKBdVrSnZ2dnUVZ7q6dnZ2d@lyse.net> <kfnzk8nygrh.fsf@x-alumni2.alumni.caltech.edu>
Message-ID <UtqdnUI7L6_86FXSnZ2dnUVZ8oSdnZ2d@lyse.net> (permalink)

Show all headers | View raw


On 01/06/2012 03:15, Tim Rentsch wrote:
> David Brown<david.brown@hesbynett.no>  writes:
>
>> On Thu, 31 May 2012 13:57:58 -0700, Tim Rentsch wrote:
>>
>>> David Brown<david.brown@hesbynett.no>  writes:
>>> [snip]
>>
>> OK - this is the main point I've learned with this thread (and the reason
>> I asked in the first place).  I know how to use such unions, I knew they
>> worked in practice - know I also know they work in theory (assuming, as
>> you say, the underlying representations are known).
>
> Good deal.
>
>
>>>> 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.
>>>
>>> This approach gives undefined behavior, for several different reasons,
>>> as others have explained.  There's a good chance it will work, but
>>> certainly that's not guaranteed under the Standard.
>>>
>>
>> OK.  I'm not entirely confident about /why/ this is not correct according
>> to the standard, and it seems to be in conflict with other things I've
>> read.  But either way, it leads to the same conclusion - it can't be
>> relied on to work, and so should not be used.
>
> For the same reason (among others) you were concerned in the
> first place, ie, aliasing rules.  You have something that is a
> float, and in particular a float not in a union, and you access
> it through a pointer to a union type!  It's possible -- and I'm
> not sure about this -- that the Standard does indeed allow this
> under effective type rules.  However, it's a grey area, and
> because of that compilers may take liberties with what kinds of
> optimizations that allow in such cases.  In almost all cases
> accessing something through a pointer converted to a type
> not the same as that of the target is best avoided.  There
> also are alignment and padding byte issues, as others have
> mentioned;  no reason to start down that path when there
> is another one that is easier and safer.

I my cases, I know that alignment and padding are not an issue.  But I 
fully agree that it is at best a grey area, and should therefore be 
avoided.  I was just saying that I'm not sure that it is a "black" area. 
  But as the whole point of my questions here was to find the safest 
"white" areas, grey is out too!

Casts to unions are discussed in the gcc documentation as a gcc 
extension, and are safe to use (carefully) with gcc - but while I often 
use various gcc ports, I also use other compilers, so gcc extensions are 
not a solution.

>
>
>>>> Does anyone know of other ways that are strictly valid and defined in
>>>> C99, and that also are efficient in use (I'd like to avoid things like
>>>> casting back and forth between char or char pointers, or volatile
>>>> accesses, etc.)?
>>>
>>> The union method is well-defined (modulo the proviso about type
>>> representations) and should work just fine.  Since you are using C99,
>>> this approach can be coded more directly using compound literls, viz.,
>>> (I am using 'unsigned' rather than 'uint32_t' but they are the same on
>>> my system):
>>>
>>>      float
>>>      negate_float( float x ){
>>>          typedef union { float f; unsigned u; } UF;
>>>          return  (UF){ .u =  (UF){ x }.u ^ 0x80000000  }.f;
>>>      }
>>>
>>> Compiling this function with gcc (using -O2 or -O3), the generated code
>>> looks pretty good, about what I'd expect and also as good as I think you
>>> would hope for.  If an 'inline' qualifier is added to the function
>>> definition, then generated code for a call is just three instructions
>>> (this is on an x86), ie, load, xor, store, and no floating point
>>> instructions.
>
> [Note that the quoted function body had line-wrapping issues not
> present in the original, which I have repaired above.]

I noticed that too - sometimes mail/news programs mess up code formatting.

>
>> I like the idea, as it is an elegant and efficient solution.  However,
>> I'm a big fan of clear and explicit code, and my code has to be easily
>> understood by others (even those not yet well versed in C99) - I think
>> this looks a bit convoluted for common use.  But in some circumstances,
>> it could be the best solution.
>
> I am also a fan of clear code.  I suspect the issue here is
> not lack of clarity but lack of familiarity;  compound literals
> were introduced in C99 and few people use them.  So there is
> something of a chicken and egg problem.

That's exactly the point - it's a matter of usage.  I have used compound 
literals occasionally, because sometimes it makes the code clearer, but 
I have to do so with care so that the code is clear to people unused to 
them.

> However, if you
> aren't comfortable using compound literals, we can still
> write a simple function using a direct, functional style
> (disclaimer: not compiled):
>
>     float
>     negate_float( float x ){
>        typedef union { unsigned u; float f; } UF;
>        const UF   f = { .f = x },   u = { .u = f.u ^ 0x80000000 };
>        return  u.f;
>     }
>

I'd split the line in two:
	const UF f = (UF) { .f = x };
    	const UF u = (UF) { .u = f.u ^ 0x80000000 };

Then I think it is clear even to people unfamiliar with compound literals.

> The type punning change from float to unsigned happens at 'f.u',
> and from unsigned to float happens at 'u.f'.  Taking a functional
> approach allows the two union variables to be 'const'.  Personally
> I think this functional style is easier to understand than an
> imperative one where a single union object is serving two different
> purposes.
>
>
>> With my brief testing (with gcc on amd64), all versions of the functions
>> gave the same code, including the movement of data onto the stack
>> mentioned elsewhere in the thread.  But that's not a concern for me, as
>> that is not one of my targets.
>
> Another reason for writing this function using a functional style
> rather than an updating assignment is that it's often easier for a
> compiler to optimize such code, mapping as it does very
> straightforwardly onto a single-assignment canonical form.  Gcc
> is pretty clever at optimizing, but for another compiler of
> unknown abilities I think there is a better chance of it
> optimizing nicely if this kind of functional approach is taken.

Exactly - writing clear and straightforward code gives the compiler the 
best chance.

Thanks for your suggestions and comments.

mvh.,

David

Back to comp.lang.c | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Aliasing in C99 David Brown <david.brown@hesbynett.no> - 2012-05-31 09:01 -0500
  Re: Aliasing in C99 James Kuyper <jameskuyper@verizon.net> - 2012-05-31 10:21 -0400
    Re: Aliasing in C99 David Brown <david.brown@hesbynett.no> - 2012-05-31 14:17 -0500
  Re: Aliasing in C99 Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-05-31 10:52 -0400
    Re: Aliasing in C99 Xavier Roche <xroche@free.fr.NOSPAM.invalid> - 2012-05-31 16:55 +0200
      Re: Aliasing in C99 Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-05-31 11:47 -0400
    Re: Aliasing in C99 Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-31 14:21 -0700
  Re: Aliasing in C99 Xavier Roche <xroche@free.fr.NOSPAM.invalid> - 2012-05-31 16:53 +0200
    Re: Aliasing in C99 David Brown <david.brown@hesbynett.no> - 2012-05-31 13:47 -0500
      Re: Aliasing in C99 Xavier Roche <xroche@free.fr.NOSPAM.invalid> - 2012-05-31 21:10 +0200
  Re: Aliasing in C99 Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-31 13:57 -0700
    Re: Aliasing in C99 David Brown <david.brown@hesbynett.no> - 2012-05-31 16:52 -0500
      Re: Aliasing in C99 Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-31 18:15 -0700
        Re: Aliasing in C99 David Brown <david@westcontrol.removethisbit.com> - 2012-06-01 09:52 +0200
          Re: Aliasing in C99 Tim Rentsch <txr@alumni.caltech.edu> - 2012-06-01 09:07 -0700

csiph-web