If the chosen implementation of this format in the OP isn't yet set-in-stone, perhaps this can help.
You could create a wrapper class that manages a word of the relevant size and returns/sets the relevant parts for a caller, as suggested by user3528438.
Or you could do what I do (albeit not for CANs) and create multiple wrappers: For each 'subfield', make a struct
holding a uint_or_whatever_t
plus member functions/operator
s to extract the relevant bits. Then union
multiple such struct
s together.
Wait! Put away your type-punning pitchforks! The latter pattern is the exception, specifically allowed by the Standard for interleaved reads of members in the common initial sequence (look it up) of standard-layout struct
s in a union
- ensuring these are definitely accessing the same memory/not optimised away.
Having determined we're in Defined Behaviour Land, the real benefit is how this neatly avoids the implementation-defined layout of 'native' bitfields: you, not your compiler, define how relevant bits are get/set. Sure, you can manually do this in C, using inline bitmanip or helper functions - I used to - but by using a class, all the cruft is hidden in the class implementation, as it should be.
e.g.
class CanPriority {
// the raw memory
uint32_t m_raw;
public:
// getter/setter methods or operators
uint8_t get() const { /* extract, shift... */ }
// etc.
};
class CanReserved {
uint32_t m_raw;
public:
uint8_t get() const { /* ... */ }
// ...
};
union CanId {
CanPriority priority;
CanReserved reserved;
// etc.
};
fwiw, I've done some pretty wild stuff with some very elaborate versions of this pattern for other cases - imagine what you can do when template
s are added, for instance - and only ever had perfect results, even at -O3 -flto
.