3

I often use memcpy to copy a struct in C/C++. I see someone use equal sign directly copy struct in C/C++. For example:

struct A { char* name; int value; };
struct B { struct A happy[10]; }; 

struct A a1, a2;
struct B b1, b2;
memcpy(&a1, &a2, sizeof(struct A));
b1 = b2;

What's the efficiency difference between memcpy and equal sign ?

user657267
  • 20,568
  • 5
  • 58
  • 77
linrongbin
  • 2,967
  • 6
  • 31
  • 59

3 Answers3

5

Now that the c++ tag has beed removed, we are talking C and not C++.

Assuming a1and a2 being variables of the same struct type

memcpy(&a1, &a2, sizeof(struct A));

and

a1 = a2;

do exactly the same thing.

But it is entirely up to the compiler if the assignement operator actually uses memcpy or not.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
4

C++

In C++ a structure can be plain old data (C types) or complex - requiring construction and copy constructors to be called.

the difference between memcpy and = is that = works.

When = is applied to a complex structure, it copies each of the members following their rules. When = is applied to a simple structure (plain-old-data or POD) then it does a "memcpy".

C

In C complex copies were not originally allowed, so some old code would memcpy over using =. In C they equate to the same operation.

mksteve
  • 12,614
  • 3
  • 28
  • 50
2

C != C++... let's assume C case, where you cannot overload the assignment operator.

It's worth having a look to the output of clang for your test case:

struct A { char* name; int value; };
struct B { struct A happy[10]; }; 

void foo() {
  struct A a1, a2;
  struct B b1, b2;
  memcpy(&a1, &a2, sizeof(struct A));
  b1 = b2;
}

Running the following command makes clang output the LLVM bytecode:

clang -S -emit-llvm foo.c -o -

Which outputs

; Function Attrs: nounwind uwtable
define void @foo() #0 {
  %a1 = alloca %struct.A, align 8
  %a2 = alloca %struct.A, align 8
  %b1 = alloca %struct.B, align 8
  %b2 = alloca %struct.B, align 8
  %1 = bitcast %struct.A* %a1 to i8*
  %2 = bitcast %struct.A* %a2 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* %2, i64 16, i32 8, i1 false)
  %3 = bitcast %struct.B* %b1 to i8*
  %4 = bitcast %struct.B* %b2 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* %4, i64 160, i32 8, i1 false)
  ret void
}

The interesting part is that in both case (call to memcpy or assign operator) a call to @llvm.memcpy.p0i8.p0i8.i64 is generated!

serge-sans-paille
  • 2,109
  • 11
  • 9