1

I have the following two structures. I need to copy d, e, f from source to destination using memcpy and offsetof. How can I do this?

struct source
{
    int a;
    int b;
    int c;
    int d;
    int e;
    int f;
};

struct destination
{
    int d;
    int e;
    int f;
};
ArjunShankar
  • 23,020
  • 5
  • 61
  • 83
Sandeep
  • 69
  • 1
  • 9

3 Answers3

5

Generally, You cannot reliably do it using memcpy, because the compiler is allowed to pad the two structures differently. So the safest way of performing a partial copy would be to assign the three fields individually.

However, since the compiler inserts padding only between members with different alignment requirements, in your specific case you can use memcpy like this:

struct source s {1,2,3,4,5,6};
struct destination d = {100, 200, 300};
memcpy(&d, ((char*)(&s))+offsetof(struct source,d), offsetof(struct source,f)-offsetof(struct source,d)+sizeof(int));

The offset of destination's d is guaranteed to be zero because it is the initial member of the structure. Since members d, e, and f have identical alignment requirements, the padding, if any, will go after them in the struct destination, and before or after them in the struct source.

Cast to char* is required because the offset is expressed in bytes.

The expression

offsetof(struct source,f)-offsetof(struct source,d)+sizeof(int)

is the length of the run between d and f, inclusive. Note that using sizeof(struct destination) is not safe, because it may have padding at the end which is not present in struct source, causing a read past the allocated memory.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    And although required by the assignment, in both cases the use of `offsetof` is counter-productive. `((char*)(&s))+offsetof(struct source,d)` could be `&s.d`, and `offsetof(struct source,f)-offsetof(struct source,d)` could be `(char*)&s.f - (char*)&s.d`. – Steve Jessop May 10 '12 at 13:45
  • @SteveJessop Absolutely! `&s.d` is much cleaner than using `offsetof`. – Sergey Kalinichenko May 10 '12 at 14:00
  • I wonder whether the marker would give a pass for doing it properly, but throwing in an `offsetof` somewhere harmless ;-) Normally `offsetof` is for uses where you either don't have an instance of the struct to act on (e.g. statically asserting that your structure matches some specification byte-for-byte, like a file format or internet protocol) or else you want to abstract away the name of the field (for example a visitor where you want to parameterize which field you look at on each object visited). – Steve Jessop May 10 '12 at 14:05
1

As "dasblinkenlight" said, this can't be done reliably by memcpy due to possible padding. You may however do something like this:

struct Part1
{
    int a;
    int b;
    int c;
};

struct Part2
{
    int d;
    int e;
    int f;
};

struct source
{
    struct Part1 p1;
    struct Part2 p2;
};

struct destination
{
    struct Part2 p2;
};

// ...
src.p2 = dst.p2;
valdo
  • 12,632
  • 2
  • 37
  • 67
  • @interjay: I've removed inheritance. Now it's a member (which is the same at the binary level) – valdo May 10 '12 at 16:53
0

For this scenario you can also use int pointer to the source and destination structures and then assign the value in destination pointer and decrease both source and destination int pointer.

The snippet of the code is as follows:-

struct destination * my_copy (struct source *pfSrc, struct destination *pfDes)
{
  int *pSrc = (int *)pfSrc;
  int *pDes = (int *)pfDes;
  pSrc += (sizeof (struct source)/sizeof (int)) - 1;
  pDes += (sizeof (struct destination)/sizeof (int)) - 1;
  do
  {
    *pDes = *pSrc;
    pSrc--;
  }while (pDes-- != (int *)pfDes);
return pfDes;
}
Chandan
  • 23
  • 4