Home > Net >  Copying struct members: memcpy vs assignment
Copying struct members: memcpy vs assignment

Time:05-21

When copying members of structs or entire structs, is there a reason to use memcpy as opposed to normal assignment = operator?

CodePudding user response:

There is a reason to use memcpy. If you used memset(ptr, 0, sizeof *ptr) in the first place to ensure that the padding between structure members, and at the end, is all zero bytes, then memcpy will copy that all-zero padding.

Member-wise initialization is not required to clear the padding and, similarly, member-wise assignment isn't required to copy it.

Clearing the padding may be important for security, like if you are sending the image of as struct over the network or storing it in a file, since the padding can leak secrets.

CodePudding user response:

Let's assume, version 1 of your code looks like this:

struct Foo_tag;
typedef struct Foo_tag Foo_t;
struct Foo_tag {
  int a;
};

And let's consider to have a function, performing a copy of such a struct:

bool copyFoo(const Foo_t* source, Foo_t* destination) {
  if (NULL == source || NULL == destination) return false;
  // version 1: element-wise assignment.
  destination->a = source->a;
  // version 2: memcpy() solution.
  memcpy(destination, source, sizeof(Foo_t));
  // version 3:
  *destination = *source;
  return true;
}

If, later on during the life time of the code base, Foo needs to be altered to contain a second member, you will need to also update the implementation of copyFoo(), if it is done with member-wise assignment (version 1). If it is implemented along version 2, there is no risk to "forget" to update the copyFoo() function and to end up with a struct, only partly initialized.

And C, being C (the evil language, which helps you messing up), there is no compiler help to expect, which would warn you, that the struct is only partially initialized.

Version 2 also has some intrinsic risk, though. If the newly added members of the struct are not trivial and extra code is required, it is just as likely, to forget to add the required lines as in version 1.

// new version of Foo_t
struct Foo_tag {
  int a;
  const char* message;
};

The new, non-trivial member "message" needs to conform to some "design decisions", which cannot be expressed in C. If message usually points to a string literal in the program, just copying the pointer would be fine. But, on the other hand, if the string, Foo_t::message points to is dynamically allocated, it is unclear, when the string can be freed again (2 instances of Foo_t now point to the same string). So, copying the string is probably the safest approach, which, of course is not accomplished with the memcpy() approach.

Version 3 is both in terms of risk and reward, the same as version 2.

CodePudding user response:

No​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​.

  • Related