Search code examples
cmemcpyoffsetof

How to do a 'memcpy' between different structures using 'offsetof'?


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;
};

Solution

  • 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.