This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: strict aliasing rule and examples


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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]