1

I am trying to copy part of a large structure and I was hoping I could use pointer arithmetic to copy chunks of it at a time. So if I have the following stucture

struct {
  int field1;
  char field2;
  myClass field3;
  .
  .
  .
  myOtherClass field42;
} myStruct;
struct origionalStruct;
struct *pCopyStruct;

can I use memcpy() to copy part of it using pointer arithmetic?

memcpy(pCopyStruct, &origionalStruct.field1, 
      (char*)&origionalStuct.field1 - (char*)&origionalStuct.field23);

I know that pointer arithmetic is only valid for arrays, but I was hoping I could get around that by casting everything to (char*).

  • "I know that pointer arithmetic is only valid for arrays" Not true, it's valid inside objects. – Luchian Grigore May 12 '15 at 14:50
  • It should be `struct myStruct origionalStruct;` and `struct myStruct* pCopyStruct;` – Surajeet Bharati May 12 '15 at 14:52
  • @LuchianGrigore The difference of two pointers outside of the same array is UB and should be avoided whereever possible. – too honest for this site May 12 '15 at 19:29
  • Claudius: you shall not cast pointers to `void *`. This might hide type-errors if either side is expected to be `void *`, but is actually not. If someone told you otherwise, point him [here](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) and tell him to read the standard. – too honest for this site May 12 '15 at 19:32

3 Answers3

1

It would be best to put the fields you want to copy into a nested struct and just assign that to the corresponding field of the new struct. That would avoid writing, increases greatly readability and - least not last - maintains type-safety. All which memcpy does not provide.

offsetof() or using the addresses of enclosing fields would obviously not work if the copied fields are at the end or beginning of the struct.

struct {
    int field1;
    struct { char fields } cpy_fields;
} a, b;

a.cpy_fields = b.cpy_fields;

When using gcc, you can enable plan9-extensions and use an anonymous struct, but need a typedef for the inner:

typedef struct { char field1; } Inner;

struct {
    int field1;
    Inner;
} a, b;

This does not change existing code which can do: a.field2. You can still access the struct as a whole by its typename (provided you only have one instance in the outer struct): a.Inner = b.Inner.

While the first part (anonymous struct) is standard since C99, the latter is part of the plan9-extensions (which are very interesting for its other feature, too). Actually the other feature might provide an even better sulution for your problem. You might have a look at the doc-page and let it settle for a sec or two to get the implications. Still wonder why this feature did not make it into the standard (no extra code, more type-safety as much less casts required).

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
1

My answer only holds for c++.

Using memcpy() to copy member variables of objects breaks encapsulation and is not good practice in general. I.e. only do that if you have very good reason. It can work if you are careful, but you are making your program very brittle: You increase the risk that future changes will introduce bugs.

E.g. also see http://flylib.com/books/en/2.123.1.431/1/

fex
  • 197
  • 1
  • 13
  • I agree; just saw the C++ tag. I would recomend to clarify if this is related to C or C++ (or really an answer for both is required), as the required approach would have to be very different for each language. I for myself did expect this to be pure C-related, so the tag might be removed by the TO. – too honest for this site May 12 '15 at 15:27
0

Yes, you can do:

memcpy(pCopyStruct, &origionalStruct.field1, 
  (char*)&origionalStuct.field23 - (char*)&origionalStuct.field1);

However, you probably want to use the offsetof() macro found in stddef.h.

memcpy(pCopyStruct, &originalStruct.field1, 
  offsetof(struct myStruct, field23)-offsetof(struct myStruct, field1));

Where if field1 is at offset 0 (first in the struct) you can omit the subtraction.

For completeness, the offsetof macro can be defined as:

#define offsetof(st, m) ((size_t)(&((st *)0)->m))
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
mtijanic
  • 2,872
  • 11
  • 26
  • offsetof (aka _Offsetof() ) is standard, so you should not define it. Also, the cast would suppress type-error detection. You might use gcc-extensions to maintain that, but why would one, as gcc provides C99 compatibility (except for few constructs). – too honest for this site May 12 '15 at 15:13