Search code examples
cmemcpy

memcpy copying the wrong number of bytes


1.I have the following structure.

typedef struct
{ unsigned int ibaseRecord;
unsigned int irecordNumber;
unsigned char brecordType;
unsigned char  brevision;
unsigned int ipageNumber;
unsigned int ireserve1;
unsigned int ireserve2;
unsigned int ireserve3;
unsigned short scrc16;
} DATABASEPAGEHEADER_TypeDef;

I also have following byte buffer storing an array.

char  msg_response[]={0x9A,0x17,0x00,0x00,0x17,0x00,0x00,0x00,0x04,0x02,0x9F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xEA,0x4A,0x86};

Using memcpy, I expect to map the buffer into the structure.

 DATABASEPAGEHEADER_TypeDef * varPageHeader;
 varPageHeader=(DATABASEPAGEHEADER_TypeDef*)malloc(sizeof(DATABASEPAGEHEADER_TypeDef));
 memcpy(varPageHeader,msg_response,sizeof(DATABASEPAGEHEADER_TypeDef));

However, the result messes up. Here is the inspection I made using gdb (explore the struct). Things were fine until the ipageNumber, which I expected to have value 0x0000009f.And also later in ireserveX (x=1,2,3).

ibaseRecord = 0x179a .. (Value of type 'unsigned int')
irecordNumber = 0x17 .. (Value of type 'unsigned int')
brecordType = 0x4 .. (Value of type 'unsigned char')
brevision = 0x2 .. (Value of type 'unsigned char')
ipageNumber = 0x0 .. (Value of type 'unsigned int')
ireserve1 = 0x0 .. (Value of type 'unsigned int')
ireserve2 = 0x0 .. (Value of type 'unsigned int')
ireserve3 = 0xea230000 .. (Value of type 'unsigned int')
scrc16 = 0x864a .. (Value of type 'short unsigned int') 
(gdb) print sizeof(unsigned int)
 $7 = 0x4

Does anyone have solution to it?

problem solved. It was the struct alignment problem. Thank you for your kind help.


Solution

  • The struct members are being aligned to units of their size. So the struct has a 2-byte gap between unsigned char brevision and unsigned int iPageNumber, so that iPageNumber starts at a 4-byte boundary. I'm not aware of a standards-compliant way to remove that padding, but for GCC you can specify __attribute__((packed)):

    typedef struct __attribute__((packed)) {
        unsigned int ibaseRecord;
        unsigned int irecordNumber;
        unsigned char brecordType;
        unsigned char brevision;
        unsigned int ipageNumber;
        unsigned int ireserve1;
        unsigned int ireserve2;
        unsigned int ireserve3;
        unsigned short scrc16;
    } DATABASEPAGEHEADER_TypeDef;
    

    If you want to make this properly portable though; don't use that attribute, or memcpy at all. Instead, initialize your struct fields individually from the byte data, and consider using specifically sized data types like uint32_t instead of unsigned int.