Search code examples
c++castingbit-fieldsmemory-layout

Casting memory to union


I would like to allocate some memory, initialize it to some values and then cast different segments of this memory to different structures. Something as follows:

union structA{
  __int8 mem[3];

  struct{
    unsigned field1 : 8;
    unsigned field2 : 12; 
    unsigned field3 : 4;
  };
};

struct structB{
  __int8 mem[10];
};


__int8 globalMem[128];

structA a1 <---- &globalMem[0]
structA a2 <---- &globalMem[10]
structB b1 <---- &globalMem[30]

I tried using reinterpret_cast and I don't get any compiler error but it seems that my variables (a1, a2 and b1) are not really assigned/initialized correctly.

Any idea about why this is not working and what is the correct way to achieve something like this?

Thanks!


Solution

  • To achieve what you intend to do requires the use of a reinterpret_cast:

    structA a1 = *reinterpret_cast<structA*>(&globalMem[0]);
    structA a2 = *reinterpret_cast<structA*>(&globalMem[10]);
    structB b1 = *reinterpret_cast<structB*>(&globalMem[30]);
    

    What's wrong with this ?

    This requires extreme care, because a C++ struct is a special kind of class, and this kind of assignment does not respect the object semantic (because the content at the different globalMem addresses is not initialized as proper object unless you'd use placement new somewhere in your code).

    You could also make sure that structA is trivially copyable (is_trivially_copyable<structA>::value which fortunately is true here) before using this kind of tricks.

    In addition, there could be an issue with alignment constraints which might not be respected, as globalMem has no alignment constraint, but depending on compiler/architecture, structA could require a word alignment.

    Finally, the size of structA is not necessarily 3 as you tend to think. In fact on some compilers it will be 4, as in this online demo

    Additional remarks

    You could use standard types uint8_t instead of compiler specific type name starting with double underscore.

    Regarding alignment and size topic, I'd advise you to be very prudent about memory layout assumptions. I'd rather suggest for your globalMem to consider making it a struct of all the structures it contains, so to ensure proper object semantic and have a safe layout.