Re: [GD-General] The joy of type aliasing and C
Brought to you by:
vexxed72
|
From: Eero P. <epa...@ko...> - 2003-12-26 19:43:12
|
Brian Hook wrote:
> About a year and a half ago there was a fairly major brouhaha on the
> algorithms list about this line of code:
>
> int x = * ( int * ) &somefloat;
>
> Now, let's push aside endianess and size issues, the concern was that
> since there was "type-aliasing" that Something Bad could happen.
> Something Bad, of course, being a rather ambiguous statement.
>
> I'm aware of all the bad things that can happen if you have
> type-aliasing in conjunction with pointer aliasing, which is related,
> but that one line above doesn't seem like it should be bad _with a
> legal C compiler_.
>
> The major concern are optimizations that the compiler may make that
> affect order. For example:
>
> somefloat = 1.0f;
> x = * ( int * ) &somefloat;
>
> In theory, a heavily optimizing C compiler would see that the
> assignment to somefloat should not affect the assignment to x since
> they are incompatible types, which may allow it to decide to assign to
> somefloat _after_ the assignment to x.
>
> But that would be illegal. The C specification states that the end of
> every expression is a sequence point, and thus the assignment to
> somefloat MUST be flushed before any subsequent statements are
> executed.
>
I have understood sequence points quite differently...
I see them as rules on what I should do, not as promises
what the compiler will do. It is true that if I obey the rules
the compiler will (hopefully) provide me the illusion that it is
also doing the same. Still expecting that some value actually gets
written to memory at a certain time based on the sequence points
is IMHO incorrect. For actually getting values really written out
you need a Voodoo priest, three (black) chickens and the volatile
keyword.
I think specifically the compiler according to the latest rules
has the right to really fool with your code, because according to
the rules the float and integer values cannot be related to each
other anyways, so why would the compiler care about ordering.
> Of course, granted, using a union makes more sense and is a bit
> cleaner, I'm fine with that:
>
> union
> {
> int i;
> float somefloat;
> } u;
>
> u.somefloat = 1.0f;
> x = u.i;
>
> But according to the C standard, the above is undefined ("If the value
> being stored in an object is accessed from another object that
> overlaps in any way the storage of the first object, then the overlap
> shall be exact and the two objects shall have qualified or unqualified
> versions of a compatible type; otherwise, the behavior is
> undefined.").
>
I also pointed this at the algorithms list, apparently the union trick
is something which is specifically ok with gcc, but I agree it is
not a good general solution.
I think there is a valid answer through the pointer manipulation
though. I have heard that (someday I must purchase the standard
instead of relying on hearsay) the new rules consider char *
special so that the compiler will not do any aliasing optimisation
around it.
So converting your float variable address to char pointer, and constructing
the integer through it should be the correct way.
I just tried and gcc seems to stop the aliasing warning even
if I only do this:
float s=t;
int x= *(int *)(char *)&s;
return x;
But I am certainly not sure if that is really enough.
(Although both pointer conversions separately
should be ok)
> Anyone have something more authoritative on this issue?
>
Ooops, well you got my opinion at least...
Eero
|