Union allocation of memory isn't making sense

I am trying to write a program to mimic a BLE bicycle speed and cadence sensor. It requires a message with an unusual structure - basically an 11 byte message with octets that conform to a structure of:
byte
32 bit unsigned integer
16 bit unsigned integer
16 bit unsigned integer
16 bit unsigned integer

I created a union based on a struct with the appropriate data structure but when I look at the way the union actually holds the data it doesn't make sense to me. Below my debugging code creates the data structure with an 11 byte array as the union data, initializes with values that should let me see how the bytes are held, and then Serial.println for me to review that data.

//declare a union of type csc_data which points to a struct with data appropriate types
union csc_data{
  struct {
    uint8_t flags;
    uint32_t cumWheelRevolution;
    uint16_t lastWheelEventTime;
    uint16_t cumCrankRevolution;
    uint16_t lastCrankEventTime;
  };
  byte cscValues[11];
};

//instantiate a union of type csc_data
union csc_data myCSCdata;

void setup() {
Serial.begin(115200);
Serial.println("Start");

myCSCdata.flags = 111;  //initialize flags to indicate will have both wheel and crank revolution data
myCSCdata.cumWheelRevolution = 67305985;  //hex 04030201
myCSCdata.lastWheelEventTime = 1541;  //hex 0605
myCSCdata.cumCrankRevolution = 2055;  //hex 0807
myCSCdata.lastCrankEventTime = 2569;  //hex 0a09


Serial.println(myCSCdata.cscValues[0]);
Serial.println(myCSCdata.cscValues[1]);
Serial.println(myCSCdata.cscValues[2]);
Serial.println(myCSCdata.cscValues[3]);
Serial.println(myCSCdata.cscValues[4]);
Serial.println(myCSCdata.cscValues[5]);
Serial.println(myCSCdata.cscValues[6]);
Serial.println(myCSCdata.cscValues[7]);
Serial.println(myCSCdata.cscValues[8]);
Serial.println(myCSCdata.cscValues[9]);
Serial.println(myCSCdata.cscValues[10]);
}

What I'm EXPECTING is serial output that looks like:

111
1
2
3
4
5
6
7
8
9
10

What I'm getting is:

111
0
0
0
1
2
3
4
5
6
7

If I change the code to create a 14 element array:

//declare a union of type csc_data which points to a struct with data appropriate types
union csc_data{
  struct {
    uint8_t flags;
    uint32_t cumWheelRevolution;
    uint16_t lastWheelEventTime;
    uint16_t cumCrankRevolution;
    uint16_t lastCrankEventTime;
  };
  byte cscValues[14];
};

//instantiate a union of type csc_data
union csc_data myCSCdata;


void setup() {
Serial.begin(115200);
Serial.println("Start");

myCSCdata.flags = 111;  //initialize flags to indicate will have both wheel and crank revolution data
myCSCdata.cumWheelRevolution = 67305985;  //hex 04030201
myCSCdata.lastWheelEventTime = 1541;  //hex 0605
myCSCdata.cumCrankRevolution = 2055;  //hex 0807
myCSCdata.lastCrankEventTime = 2569;  //hex 0a09


Serial.println(myCSCdata.cscValues[0]);
Serial.println(myCSCdata.cscValues[1]);
Serial.println(myCSCdata.cscValues[2]);
Serial.println(myCSCdata.cscValues[3]);
Serial.println(myCSCdata.cscValues[4]);
Serial.println(myCSCdata.cscValues[5]);
Serial.println(myCSCdata.cscValues[6]);
Serial.println(myCSCdata.cscValues[7]);
Serial.println(myCSCdata.cscValues[8]);
Serial.println(myCSCdata.cscValues[9]);
Serial.println(myCSCdata.cscValues[10]);
Serial.println(myCSCdata.cscValues[11]);
Serial.println(myCSCdata.cscValues[12]);
Serial.println(myCSCdata.cscValues[13]);

}

I get the following:

111
0
0
0
1
2
3
4
5
6
7
8
9
10

I do not understand why I have three empty bytes after the first byte (which is holding the correct data).

Thanks for any insight.

AGS

On what board? ARM cpus don't handled unaligned data, so structures will normally be padded so that uint32 data falls on 4byte boundaries.
That means that:

stuct {
  uint8_t a;
  uint32_t b;
}

Will take 8 bytes, with 3 padding bytes between a and b.

There may be a "packed" attribute or similar to cause the compiler to leave out the padding, but I think then you'll have to write your own code to handle the unaligned int32s.

I don't understand why if you want hex values you are storing them as decimal, makes reading it difficult. For example instead of:

myCSCdata.cumWheelRevolution = 67305985;  //hex 04030201

What is wrong with:

myCSCdata.cumWheelRevolution = 0x04030201

?

The problem might be that C++ does not allow you to use a union for type punning. OK, so often it works just fine but it's undefined behaviour and might or might not work as expected. You could try defining the variables as volatile and see if that makes it work, however, in C++ you are not supposed to do this.

Testing on an UNO does produce the expected output, so it is probably related to the specific board you are using.

As @PerryBebbington suggests, this is UB undefined behaviour in C and C++.

It looks clever but can really bite you.

It is wrong to “expect” anything.

a7

Thanks everyone, it is running on an ESP32 board (Lolin Wemos 32).

I'll try it on an uno and see what happens (as noted by David_2018) and if necessary I can try shifting the data in the array prior to sending the BLE message.