Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy struct to buffer

Tags:

c

I have a structure:

struct data{
 int num1;
 int num2;
 int num3;
 int num4;
}

Now, I can convert individual elements and then put them in a buffer, but I want to copy the whole structure into a buffer(char buffer[sizeof(data)]).

Is there a way to copy ?

like image 200
Punit Avatar asked Dec 02 '22 02:12

Punit


2 Answers

memcpy can do this

Microsoft systems can use memcpy_s for an automated check on sizes

You also need to be aware of pointers inside struct data.

struct data { 
    int num1;
    char* name;
}

the content of the memory pointed by char* name will not be copied by memcpy. You will need some kind of serialization which is a little more complicated.

Here is some valid code that does it. It copies the data to and from then displays the result

struct data{
  int num1;
  int num2;
  int num3;
};

int main(int argc, char** argv)
{
   data my_data;
   my_data.num1 = 64;
   my_data.num2 = 65;
   my_data.num3 = 66;

   char buffer[20];
   memcpy(buffer, &my_data, sizeof(data));

   data copy_data;
   memcpy(&copy_data, buffer, sizeof(data));

   printf("the numbers : %d - %d - %d \n", copy_data.num1, copy_data.num2, copy_data.mum3);



   return 0;
}
like image 131
Eric Avatar answered Dec 22 '22 10:12

Eric


In your comment to this answer,

I am trying to copy this struct to a flash [memory chip]. And the Flash read/write API passes a string. – Punit 2 hours ago

you reveal that you've got an XY Problem - You're asking how to implement your idea of a solution, not how to solve your problem. You don't really want to copy a struct to a buffer, you want to write data in your struct to Flash using an API that requires a char * argument.

Others have pointed out that memcpy will do what you want. But they all involve allocating memory for this buffer in RAM. Using these approaches will work, but they'll waste time and memory. Assuming that your Flash API has a function to the effect of:

int WriteBlock(int address, char *data, int length);

and you've stored your structure in a variable called data_var, you can use your API in an identical fashion to memcpy:

int success = WriteBlock(my_address, (char *) &data_var, sizeof(struct data)

To be clearer and avoid the cast, you may wish to wrap this in a union:

union {
    struct data{
        int num1;
        int num2;
        int num3;
        int num4;
    };
    char data_arr[sizeof(struct data)];
};

This will allow you to call it with a more traditional syntax.

Note that both methods (and memcpy!) could fail if you've got a non-contiguous structure. For instance, perhaps your structure looks like this:

struct data{
 int   num1;
 char  num2;
 long  num3;
 short num4;
}

If you're on anything other than an 8-bit system, such a structure is likely (depending on your architecture) to contain gaps. For example, assuming num1 is 0x12345678, num2 is 0x9A, num3 is 0xBCDEF0123456789A, and num4 is 0xBCDE, you might have any the following (assuming that your memory is zero-initialized, and big-endian for clarity):

    /* 8-bit */
    0x1234 5678 9ABC DEF0 1234 5678 9ABC DE00
    /* 16-bit */
    0x1234 5678 009A BCDE F012 3456 789A BCDE
    /* 32-bit */
    0x1234 5678 0000 0000 0000 009A BCDE F012 3456 789A 0000 0000 0000 BCDE

In this case, you'll have to use something more ugly, like the following function:

int fillDataBuffer(struct data d, char *buffer, int len) 
{
  int i, j = 0;

  for (i = sizeof(d.num1) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num1 >> i); 
  }
  for (i = sizeof(d.num2) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num2 >> i); 
  }
  for (i = sizeof(d.num3) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num3 >> i); 
  }
  for (i = sizeof(d.num4) - 1; i >= 0 && j < len; i--, j++) {
    buffer[j] = (char) (d.num4 >> i); 
  }

  if (j >= len) {
    /* Error!  The buffer wasn't big enough. */
    return 0;
  } else {
    return 1;
  }
}

or the #pragma pack() macro, but that could make computations using the struct slower, and you'd probably rather pack it when you're going to do the buffering.

like image 38
Kevin Vermeer Avatar answered Dec 22 '22 09:12

Kevin Vermeer