This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Question about structs and unions

Hello there,

I've faced a problem that I couldn't solve. I hope you people can help me.
I want to memcpy to a struct the datum in an array.

I've done it before, and it goes like this:

memcpy((void*)(&(frame.payload),(void*)array,frameSize);

frame is a struct like this:

typedef struct tag_FRAME{
  U8    frameSize;
  CMD   payload;
}FRAME;

and this is CMD (the payload, struct to where I want the datum to be):

typedef struct tag_CMD{
  U8    id;
  union{
        CMD1    cmd1;
        CMD2    cmd2;
        CMD3    cmd3;
        CMD4    cmd4;
        CMD5    cmd5;
        CMD6    cmd6;
  }Command;
}CMD;

And CMD1 is a struct with one member, an array of chars called arrayX[4].
Let's say buffer is {0x01 , 0x00 , 0x01 , 0x02 , 0x03}
The result I get is:
id = 0x01 (Correct)
arrayX[0] = 0x05; (the size, first member of the FRAME struct)
arrayX[1] = 0x01; (first member of the CMD struct)
arrayX[2] = 0x00; (this should be the value in arrayX[0])
arrayX[3] = 0x01; (this should be the value in arrayX[1])

When debugging the address in the watch1, of the Command union inside the payload is the same address of the FRAME struct that contains the payload. If I put the id of the CMD struct to the end of it (after the union), and the frameSize of the FRAME struct to the end of it (after the CMD struct) it all works ok, the buffer is copyed correctly to the struct.

In other words, if the "normal" variables come after the structs and unions it all works as it should.

So, do anybody knows what's going on here?

  • Well, you did not mention typedef of CMD2~CMD6. I don't know if they contains more members than CMD1.
    However, I had a small test in MDK4.20 and it worked OK.

    Something offtopic:
    a) For structures and unions, it's very important to know how comiler packs it. You can check packing behaviour and options from documents of your compiler.
    b) When debugging with a testing array, you should put distinct data for test, and should not repeat. Say {'A', 'B', 'C', 'D', 'E'...}. So that you can see clearly where your data go.
    c) Also you did not mention your uC's architecture. Pay attention to endian mode of your uC.

  • Thanks for the answer, I'll take a look at the compiler's datasheet.
    CMD1 is the biggest structure in the union. And yeah I have also tested with different arrays.
    I'm using Si1020 and MC51 compiler! Thank you.

  • You should not do any array (memcpy) assigns to a union or struct, unless that array was lifted from an identical union/struct.

    While the compiler will follow a fixed set of rules when deciding padding etc, you should write your code in ways that isn't depending on these rules of the compiler.

    Any compiler that have a rule that some data types must have an align bigger than 1 would need to insert padding between id and the union Command, since Command must have the same align as the highest requirement of cmd1, cmd2, cmd3, ..., cmd6.

  • I see it. I thought that all the 8051 memory were byte aligned. And since all the unions and structs are multiple of bytes there wouldn't be any padding and I would be able to memcpy from a buffer with no problem. Thank you guys, I'll do it in other way..