How to make this union a struct instead?

I have a controller class for an x-box controller and it uses this union type to hold and pass around the controller state. The rawBuffer is the raw data from the controller and the struct basically parses all the pieces out without having to do any bitmath or shifts or other extra work.

union ControllerUnion {

			uint8_t rawBuffer[14];
			struct {

				uint16_t checkBytes;
				uint16_t buttonState;
				uint8_t leftTrigger;
				uint8_t rightTrigger;
				int16_t leftHatX;
				int16_t leftHatY;
				int16_t rightHatX;
				int16_t rightHatY;

			} values;

		};

The syntax for this is bulky though, I have to use 2 dots. nameOfUnionInstance.values.buttonState for example. I'd rather have a struct instead that has as a member a pointer to itself as a byte array that I can use to fill the data back in. Basically I want to reverse what I have above so the union is part of the struct instead of the struct being part of the union. Is there a good way to do that? For some reason I'm not seeing it. But I want to be able to load that buffer with a single memory copy and then get the values at will without having to do any extra bitmath and to be able to access the values with a single dot like nameOfSomething.rightHatX or similar.

Only thing I can think of is to make a reference variable to the inside struct.

typedef struct ControllerStruct_t{
  uint16_t checkBytes;
  uint16_t buttonState;
  uint8_t leftTrigger;
  uint8_t rightTrigger;
  int16_t leftHatX;
  int16_t leftHatY;
  int16_t rightHatX;
  int16_t rightHatY;
};

union ControllerUnion {
  uint8_t rawBuffer[14];
  ControllerStruct_t values;
} controller;

ControllerStruct_t &conValues = controller.values;

My question would be why you embed the struct in a union? Copying a struct can be done with memcpy and byte pointers.

Delta_G:
But I want to be able to load that buffer with a single memory copy and then get the values at will without having to do any extra bitmath

septillion:
...

I guess that is directed at my reply. I edited my reply before you posted the new one :wink:

Something in the line of

struct MYSTRUCT
{
...
...
};

MYSTRUCT s1;
MYSTRUCT s2;

// copy s1 to s2
memcpy((byte*)&S2, (byte*)&S1, sizeof(MYSRUCT));

And reading the man page for memcpy, the cast is not even needed.

How about using a zero sized byte array as first member of the struct?

struct Controller  {
  uint8_t rawBuffer[0];
  uint16_t checkBytes;
  uint16_t buttonState;
  uint8_t leftTrigger;
  uint8_t rightTrigger;
  int16_t leftHatX;
  int16_t leftHatY;
  int16_t rightHatX;
  int16_t rightHatY;
} values;

Instead of sizeof(rawBuffer) you obviously should use sizeof(Controller)...

You can use an anonymous struct:

union ControllerUnion {
    uint8_t rawBuffer[14];
    struct {
      ... 
    };    
};

This is standard C11, and GCC supports this as an extension for C++ and older C versions.

@sterretje, it's not about copying the struct as a whole but being able to dump a 14 bytes array of raw data in and read it back as separate variables.

I think oqibidipo nailed it, forgot you could do that. And Whandall as well although I would have never thought the compiler would allow me to me an array with size 0 :stuck_out_tongue:

But now I think about it, you could also treat it as a uint8_t array. Skip the union (and make controller only the struct) and do ((uint8_t*)&controller)[8] = 33. But I think the solutions of oqibidipo and Whandall are far prettier :stuck_out_tongue:

Whandall:
How about using a zero sized byte array as first member of the struct?

Crafty!

oqibidipo:
You can use an anonymous struct:

I didn't know it would work like that. I think that's what I'll try first. That sounds like the prettiest solution.

Delta_G:
The syntax for this is bulky though, I have to use 2 dots.

Meh. So what? Use a #define

#define foov foo.values

struct Controller foo;

septillion:
@sterretje, it's not about copying the struct as a whole but being able to dump a 14 bytes array of raw data in and read it back as separate variables.

I still don't get it. Make S1 an array of bytes and use memcpy. Or if this is e.g. a serial read, cast S2 to a byte pointer and read the data into the successive locations.

Yeah, if you can memcopy you can indeed, like I did, take the pointer of the struct. But if you want to fill it as an array the syntax gets ugly.

And yes, you could use a macro but
a) There are, as shown options without it which are safer so I would prefer them
b) It doesn't scale

@Delta_G, both options leave you with the same :slight_smile: Although I'm still very surprised you're allowed to make zero size arrays :smiley: