Unexpexted size of struct when it has been defined in arduino

I am going to create an instance of a struct and send the data from arduino to the PC through the serial port, but the size of the struct calculated by the arduino is different from that calculation in python.

typedef struct {
  float m1; //4bytes
  float m2; //4
  int s1; //2
  int s2; //2
  int g; //2
  float p; //4
}moveItem;


moveItem uploadData;


void setup() {
  Serial.begin(57600);
  while(!Serial)
  {
    
  }
  uploadData = 
  {
    0.05,
    0.06,
    3,
    3,
    2,
    0.09
  };

}

void loop() {


  writeData(uploadData);
//  serialReadData();

  delay(1000);
  

}

void writeData(moveItem value)
{
//  Serial.println(sizeof (value)); //show the size of the struct, just for testing
  Serial.write((byte *) &value, sizeof (value));
}

void serialReadData()
{
  Serial.println(uploadData.m1);
  Serial.println(uploadData.m2);
  Serial.println(uploadData.s1);
  Serial.println(uploadData.s2);
  Serial.println(uploadData.g);
  Serial.println(uploadData.p);
}

Here I define a struct with 3 float numbers and 3 integer numbers, so the size of it should be 34+32 = 18 bytes, which is the same as that calculated in python.
However, when I try to print the size of moveItem through arduino, the result is 24 instead of 18.

  Serial.println(sizeof (value));

I try to read the data in python and it gives me:

0.05000000074505806
0.05999999865889549
3
0
3
1.8367099231598242e-40

It seems like the first three numbers are correct, s2 has been allocated to g and the other two numbers get wrong.

Does anyone know what’s wrong with the code here?

The .py code is attached below:

    BINARY_STRFORMAT = '<ffhhhf' # Format to match arduino struct
    print(calcsize(BINARY_STRFORMAT))       # size of data
    
    
    
    port = get_arduino_port()
    baudrate = 57600
    ser = serial.Serial(port, baudrate)

    while ser.inWaiting()<calcsize(BINARY_STRFORMAT):
        time.sleep(0.01)
        
    arduinoData = ser.read(calcsize(BINARY_STRFORMAT))
    print(arduinoData)
    unpacked = unpack(BINARY_STRFORMAT, arduinoData)
            
    ser.close()

int is not the same size on all platforms.

Use int16_t or int32_t …or whatever to fix the size.

Also, some platforms require particular alignments, that can screw some structs.

And just to make things interesting, floats and doubles on the AVR are the same size.

Enjoy.

The compiler is free to add padding to your struct. Using the raw underlying bytes of a struct is not a portable way to serialize it. Either serialize it yourself, member by member and with the correct Endianness, or use compiler extensions such as GCC's attribute((packed)) to create a struct without padding.

Pieter

24 suggests that those are four byte ints.

The other thing to look at is the pack pragma, but I doubt it's relevant in this case.

TheMemberFormerlyKnownAsAWOL:
int is not the same size on all platforms.

Use int16_t or int32_t …or whatever to fix the size.

Also, some platforms require particular alignments, that can screw some structs.

And just to make things interesting, floats and doubles on the AVR are the same size.

Enjoy.

int16_t works, I didn’t notice that and struggle on it for a whole night :sob:
Thank you so much!

Note also what @PieterP wrote.

PieterP:
The compiler is free to add padding to your struct. Using the raw underlying bytes of a struct is not a portable way to serialize it. Either serialize it yourself, member by member and with the correct Endianness, or use compiler extensions such as GCC's attribute((packed)) to create a struct without padding.

Pieter

Yes, I just notice that.
The arduino seems serialize the struct with big-endian by default. with the extensions, it turns to the little-endian I want.
Thanks Pieter

wildbill:
24 suggests that those are four byte ints.

The other thing to look at is the pack pragma, but I doubt it's relevant in this case.

the four byte ints is the case, it has been fixed by using int16_t instead.
Thanks Wildbill

hansng:
Yes, I just notice that.
The arduino seems serialize the struct with big-endian by default. with the extensions, it turns to the little-endian I want.

The packed attribute doesn't change the Endianness. AFAIK, most Arduinos and most desktop computers are Little-Endian these days. Network byte order is Big-Endian. Python uses the system's Endianness by default.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.