i'm relatively newer in C and i have some problems to memcpy a struct in a buffer;
I have this struct:
`typedef struct {
uint8_t size_of_payload;
uint8_t command;
unsigned char* payload;
}__attribute__((packed)) mystruct``
and i want to copy in a tx_buffer[SIZE] the values of this struct, including the value pointed by payload. payload point to an array of char with a size equals to the size_of_payload .
memcpy(&tx_buffer,&mystruct,sizeof(mystruct));
copies only the value of payload address.
It is possible do this?
CodePudding user response:
Well it isn't possible to do it in one simple call. You will have to do it 'manually'. memcpy can only copy one memory region to an other. Your source memory region isn't structured the way you want it at the destination, so will have to do it manually. Let's first copy the first two fields
memcpy(&tx_buffer 0*sizeof(uint8_t),&mystruct.size_of_payload, 1*sizeof(uint8_t));
memcpy(&tx_buffer 1*sizeof(uint8_t),&mystruct.command, 1*sizeof(uint8_t));
What we do here, is copy the first element to position zero of tx_buffer, and the second to position 1 byte after that. For the string we don't know the length. We could find it and do a memcpy, but there is a convenient alternative:
strcpy(&tx_buffer 2*sizeof(uint8_t), mystruct.payload)
CodePudding user response:
Use a flexible array member. You'll have much simpler code:
typedef struct {
uint8_t size_of_payload;
uint8_t command;
uint8_t payload[];
} mystruct;
Allocate a structure:
mystruct *allocMyStruct( uint_8 command, uint8_t size, uint8_t *payload )
{
mystruct *m = malloc( sizeof( *m ) size );
m->size_of_payload = size;
m->command = command;
memcpy( m->payload, payload, size );
return( m )
}
Copy:
mystruct *m = ...
.
.
.
// copy *ALL* the fields and the payload
memcpy( txBuffer, m, sizeof( *m ) m->size_of_payload );
Free a structure:
mystruct *m = ...
.
.
.
free( m );
The only drawback to a flexible array member is you can't allocate them as local or static variables.
You can't do
mystruct m;
when you're using flexible array members.
But compared to having a uint_t *payload
pointer in the structure that pretty much has to be allocated dynamically, in reality there's no flexibility lost.
There's no reason not to use a flexible array member in a case like this.
CodePudding user response:
This whole setup seems a bit strange to me. Why the need to "flatten" the structure? Or if the need is justified, why was this structure layout chosen? Anyway, will try to exemplify (what I consider) the easiest way (which from other criteria wouldn't be the best).
Since the structure contains a member which is a pointer (a level of indirection), it can't be done in one go.
In this particular case (as the pointer is the last member), the approach is to:
- Copy the contents of the struct till the pointer member
- Copy the contents of the dereferenced pointer member (based on the size member)
Note that for more complex structures, with alternating pointer and regular members, you'd need one memcpy call for the 1st member(s) of the same type one additional call for each consecutive member types (normal -> pointer, pointer -> normal, pointer -> pointer).
code00.c
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define BUF_DIM 0xFF // Make sure it's large enough
typedef struct {
uint8_t size_of_payload;
uint8_t command;
unsigned char *payload;
} __attribute__((packed)) Data;
size_t dataSize(const Data *pData)
{
if (pData == NULL)
return 0;
return offsetof(Data, payload) pData->size_of_payload;
}
size_t copyData(const Data *pData, uint8_t *pBuf)
{
size_t sz = dataSize(pData);
if (sz == 0)
return 0;
size_t ofs = offsetof(Data, payload);
memcpy(pBuf, pData, ofs);
memcpy(pBuf ofs, pData->payload, pData->size_of_payload);
return sz;
}
int main()
{
unsigned char array[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'c', 'd' };
Data data = { sizeof(array), 123, array };
uint8_t buf[BUF_DIM] = { 0 };
copyData(&data, buf);
size_t ds = dataSize(&data);
printf("Size: %ld\nBuf:\n", ds);
for (size_t i = 0; i < ds; i)
printf("0xX(%c) ", buf[i], buf[i]);
printf("\nDone.\n");
return 0;
}
Output:
(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q071451221]> ~/sopr.sh ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [064bit prompt]> ls main00.c [064bit prompt]> gcc -o main00.exe main00.c [064bit prompt]> ./main00.exe Size: 16 Buf: 0x0E() 0x7B({) 0x30(0) 0x31(1) 0x32(2) 0x33(3) 0x34(4) 0x35(5) 0x36(6) 0x37(7) 0x38(8) 0x39(9) 0x41(A) 0x42(B) 0x63(c) 0x64(d) Done.