2

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!

Christophe
  • 68,716
  • 7
  • 72
  • 138
Ali
  • 288
  • 3
  • 10
  • 4
    Bitfield alignment and padding is implementation defined. You will need to investigate whether or not your compiler added padding to your structure with the bitfields. Highly likely. – Sam Varshavchik Nov 23 '16 at 19:56
  • Also using a signed underlying type (`__int8 `) might not be the best idea. – πάντα ῥεῖ Nov 23 '16 at 19:58
  • 1
    try to wrap your program with `pragma pack(push,1) PROGRAM pragma pack(pop)` It should eliminate any padding problems as Sam Varshavchik mentioned. – Eliran Abdoo Nov 23 '16 at 20:01
  • What is __int8? This is not something which C++ defines. – SergeyA Nov 23 '16 at 20:09
  • I was trying to use __int8 (or any other type) to have consistency between my definitions and also to overcome the alignment problem between my globalMem and instantiated objects of structA and structB – Ali Nov 23 '16 at 20:14
  • Is placement new operator the keyword you are looking for? See http://stackoverflow.com/q/222557/6695750 – ralfg Nov 23 '16 at 21:45

1 Answers1

1

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.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • but this only copies part of globalMem to a1, etc. It really doesn't "map" a1, a2 and b1 to parts of globalMem. – Ali Nov 23 '16 at 20:18
  • @Ali there are a couple of issues on you layout (see edit), which makes me think that your mapping control takes wrong assumptions (starting with the size of struct A). I invite you to look at this online demo: http://ideone.com/K3PYpT where you'll see that a prpeprly initialized object is properly copied despite the reinterpret cast. However, reinterpret cast usually spots a tricky design that's worth reconsidering. – Christophe Nov 23 '16 at 20:59