0

I'm receiving byte buffer array and trying to copy it to a structure:

my structure is:

typedef struct mydata_block
{
    uint8_t cmd;
    uint32_t param;
    char str_buf[10];
    uint32_t crc32;
} mydata_t;

first, the program that sends the data as following:

blockTX.cmd = 2

blockTX.str_buf = "eee789"

blockTX.param = 1001

blockTX.crc32 = 3494074521

-

02-00-00-00-E9-03-00-00-65-65-65-37-38-39-00-00-00-00-00-00-99-58-43-D0

when the data is recieved im copying the data to the structure using the memcpy code below:

    memcpy((uint8_t *)&blockRX,(uint8_t *)usbd_cdc_buffer,sizeof(blockRX));

everything looks fine, but not the cmd (its 1 byte but there is padding? in structure?) how do i fix this?

12
  • 9
    Do not use memcpy. You need to parse the byte stream, "understand" the value individually and write them explicitly and individually to the members of the struct. Any assumption on padding, sizes, endianess etc. will make your program non-portable and prone to fail in the future. Commented Jul 19, 2018 at 7:09
  • 1
    There might be padding it is compiler specific. I'm concerned about the mixture of types, for example blockTX.str_buf = "eee789"; is not the way to copy a string, you should use strcpy. Commented Jul 19, 2018 at 7:10
  • @cdarke well, sorry but that blockTX code was not a c code its in c# in pc.. and it was actually: blockTX.str_buf = Encoding.ASCII.GetBytes("eee789"); but i striped it just to show the data not the code. Commented Jul 19, 2018 at 7:11
  • 7
    Longer, slower yes. But long slow correct is better than short fast wrong or short fast non-reusable. Same goes with the need to change the code to understand new message structure. Commented Jul 19, 2018 at 7:18
  • 1
    @AndrewHenle Good point. Lets compromise on "Even if longer slower." ;-) Commented Jul 19, 2018 at 14:35

1 Answer 1

4

Transfering data needs to consider padding, sizes, endianess etc so you need to generate and parse the byte stream correctly. You can use something like googloe protobuf to serialize and deserialize your data protable and comfortable.

But if you must you can give the structure the packed attribute. This removes all the padding and alignment restrictions. That lets you memcpy() the struct without paddings but at the cost of slower access to the members of the struct itself. There are only two good reasons to do this:

  1. The alignemnt and padding of the struct is determined by forces outside your control (has to match hardware or 3rd party software).
  2. As intermediate step to converting the data into host format.
Sign up to request clarification or add additional context in comments.

5 Comments

Also, packing a structure can result in code that doesn't run. It gets used a lot because x86 allows it. Other hardware exists that doesn't allow unfettered access to misaligned data.
If packing creates code that doesn't run then your compiler is broken. The packed attribute tells the compiler that no padding or alignment is used for the struct. That also means access to any member of the struct has to handle unaligned access. For example on ARM reading a struct { int x; } __attribute((packed)) results in 4 separate byte reads, shifts and ors. Hence the much slower part.
So GCC is broken? #pragma pack is playing with fire on many non-x86 platforms.
Note that you still have the issue of endianness.
@AndrewHenle Nothing in there about structure access being broken. When taking the address of a members of a packed struct you have to always make a pointer to a packed struct too, e.g. typedef struct { int32_t unaligned_int32; } __attribute((packed)) unaliged_uint32p;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.