Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
| 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) |
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
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