Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get sizeof anonymous struct inside union

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.

like image 330
gkimsey Avatar asked May 07 '14 18:05

gkimsey


2 Answers

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;

like image 86
Ben Voigt Avatar answered Nov 09 '22 01:11

Ben Voigt


This will work:

union
{
  struct
  {
    unsigned char a;
    unsigned char b;
    // ... Some other members ...
    unsigned char w;
  };
  unsigned char bytes[1];
} myUnion;
like image 1
TonyK Avatar answered Nov 09 '22 02:11

TonyK