Question

I know that for the code below, "Illegal" below is undefined (while some compilers allow it), because union member "a" is active, and then we read from union member "b". The question is, does the code in "AmILegal" fix it, or am I doing something scary and even more obscure? Can I use memcpy to achieve the same effect or is there another undefined behaviour I am invoking there?

EDIT: Maybe the example is not clear enough. All I want to do is activate the other member. So I am changing float to int. Although it seems dumb, it is closer to the real case. Read BELOW the code.

(Is it for some reason disallowed to copy one union member into another?)

struct Foo
{
    union Bar
    {
        int a[4];
        int b[4];
    };

    void this_is_Illegal()
    {
         a[0]=1;
         a[1]=2;
         a[2]=3;
         a[3]=4;
         std::cout<<b[0]<<b[1]<<b[2]<<b[3];
    }

    void but_is_this_Legal?()
    {
         a[0]=1;
         a[1]=2;
         a[2]=3;
         a[3]=4;

         b[0]=a[0];
         b[1]=a[1];
         b[2]=a[2];
         b[3]=a[3];
         std::cout<<b[0]<<b[1]<<b[2]<<b[3];
    }


    void this_looks_scary_but_is_it?()
    {
         a[0]=1;
         a[1]=2;
         a[2]=3;
         a[3]=4;
         //forget portability for this q, assume sizeof(int)==sizeof(float)
         //maybe memmove works here as well?
         memcpy(b, a, sizeof(int)*4)

         std::cout<<b[0]<<b[1]<<b[2]<<b[3];
    }

};

If all of the above does not sound very useful, think that a is in truth an _m128 unioned with a float[4]. The bit representation is exact and correct, always. At one point in time, you WILL need to actually use it, and you NEED to have it in main memory as an array of floats. The "copy instruction" is in truth an _mm_store_ps from the _m128 union member to the float[4] member. Hence the question about the memset - maybe it is the more exact example to what I need...

Was it helpful?

Solution

The second function is perfectly legal - but doesn't do the same thing, since it will perform an int to float conversion rather than leaving the bits unchanged.

To be honest I would just stick with the first one - the behaviour is technically undefined, but I suspect it just does the right thing for you.

The third one switches one form of undefined behaviour for another (once you've written arbitrary bytes into a float, anything could happen). But if you know the bytes really represent a valid floating point value, it's fine.

OTHER TIPS

the this_is_illegal,this_is_legal? pretty much the standard way to use enums ;)

but the memcpy will not work, becayse &a and &b are at the same address because of the enum and memcpy will do nothing

because &a and &b are at the same address you can do some intresting things with the enum - in your case interpret a float as an integer is the built-in feature of your enum, but auto casting can't be triggered, because they are at the same address

you might want to look at attribute((packed)) because it helps to declare protocol structs/enums

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top