Re: strict aliasing rule and examples

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Mojmir Svoboda wrote:
hello,
i've just encountered some code breaking the aliasing rule:

#include <cstdio>

unsigned EndianSwap (unsigned data) {
    return (data << 24 & 0xff000000) | (data << 8 & 0x00ff0000)
        | (data >> 8 & 0x0000ff00) | (data >> 24 & 0x000000ff);
}
float EndianSwap (float data) {
    unsigned res = EndianSwap(*reinterpret_cast<const unsigned *>(&data));
    return *reinterpret_cast<float*>(&res);
}
int main () {
    float aa = 123.456f;
    float bb = EndianSwap(aa);
    printf("swap: %f -> %f\n", aa, bb);
}

the thing is that i can see what happens if -O3 and -fstrict-aliasing
is on, but i'd like to know what's going on under-the-hood (if it is
almost-human explainable):

If you are to understand this at all, you *must* read the appropriate
section of the ISO C standard.  This is Section 6.3.2.3.  Search for
iso-9899 on the web.  This section tells you which pointer conversions are
defined, and any pointer conversion not defined in that section has no
meaning.

i mean - what is compiler doing to optimize the whole swap code out?

The code is meaningless, so the compiler doesn't have to do anything
at all. What actually happens is that the compiler can see that the statements have no effect, so the whole lot gets dropped on the floor.

and yet another (perhaps related) thing: let's have following code:

struct vect {
  float x, y, z;
  float & operator[] (int i) { return *(&x + i); }
};

i know that there is a potential hazard with padding, but
gcc guru of mine told me that this is in fact breaking of the aliasing
rule too, but after few beers i stopped following his arguments.
is it? how does it break the rule?

It's not one of the well-defined conversions in Section 6.3.2.3.

Basically, the rule is this: you cannot take the address of an object
and through pointer type conversion create an lvalue of an incompatible
type.

gcc has a useful extension, which is supported my many compilers:

float EndianSwap (float data) {
  union
  {
    float fd;
    unsigned ud;
  } u;
  u.fd = data;
  u.ud = EndianSwap(u.ud);
  return u.fd;
}


This is much nicer anyway, and it much more clearly describes what you're
trying to do.

Andrew.

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux