I'm hoping this isn't a duplicate question, but I've searched in some detail and haven't found my exact case before.
I have a simple struct that I also want to be able to access as a simple byte array
union
{
struct
{
unsigned char a;
unsigned char b;
// ... Some other members ...
unsigned char w;
};
unsigned char bytes[sizeof( what? )];
} myUnion;
Notice the struct is not named and it also isn't given its own member name. This is so that I can use myUnion.a
to access that member, and not myUnion.myStruct.a
.
However, without some name, how can I get the size of the struct for myUnion.bytes[]
other than manually calculating it each time I change something?
My current workaround is to use a #define
to make up for the myUnion.myStruct
problem, but that has the negative side-effect of ruining my auto-complete in the editor, and also makes my data structures harder to understand.
Any ideas?
Note: This is running on an 8-bit processor. There are no issues with word alignment and such. That said, any caveats should probably be stated so someone else doesn't use a proposed solution inappropriately.
Just get rid of the union. You can safely access any trivially-copyable structure as a byte array by casting its address to char*
, and casting won't run afoul of the undefined behavior when you read from an inactive union member.
struct
{
unsigned char a;
unsigned char b;
// ... Some other members ...
unsigned char w;
// array-style access
unsigned char& operator[](size_t i)
{ return reinterpret_cast<unsigned char*>(this)[i]; }
} myStruct;
The reason that it's safe to cast in this manner is that char
is a special exception from the strict aliasing restrictions.
For unions, the only special permission you get is for access to members which are "standard-layout structs which share a common initial sequence"... and an array unfortunately does not meet the criteria for a "standard-layout struct". I would like to see that rule change to "standard-layout struct or aggregate", but in the current wording the union version isn't safe.
In C99, but not any version of C++, you could use a flexible array member, and not need to specify the size at all.
union
{
struct
{
unsigned char a;
unsigned char b;
// ... Some other members ...
unsigned char w;
};
unsigned char bytes[];
} myUnion;
This will work:
union
{
struct
{
unsigned char a;
unsigned char b;
// ... Some other members ...
unsigned char w;
};
unsigned char bytes[1];
} myUnion;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With