Preference between memcpy and dereference
For the exact same reason you mentioned, I'd prefer method 2 (the dereferencing one). Memcpy does a byte-by-byte copy AND has the overhead of a function call, while the dereferencing does the copy only, and doesn't have the extra overhead.
Dereferencing and assigning is also more readable (especially when you omit the superfluous parentheses:
*dest = *src;
)
I tried to run this with Google's benchmark:
#include <benchmark/benchmark.h>
#include <stdio.h>
#include <string.h>
typedef struct {
int foo;
int bar;
int a;
int b;
int c;
int d;
int e;
int f;
int g;
} compound;
static void copy_using_memcpy(benchmark::State& state) {
compound a = {0, 0, 0, 0, 0, 0, 0, 0, 0};
compound b = {0, 0, 0, 0, 0, 0, 0, 0, 0};
compound* pa = &a;
compound* pb = &b;
for (auto _ : state) memcpy(pa, pb, sizeof(compound));
}
static void copy_using_deref(benchmark::State& state) {
compound a = {0, 0, 0, 0, 0, 0, 0, 0, 0};
compound b = {0, 0, 0, 0, 0, 0, 0, 0, 0};
compound* pa = &a;
compound* pb = &b;
for (auto _ : state) *pa = *pb;
}
BENCHMARK(copy_using_memcpy);
BENCHMARK(copy_using_deref);
BENCHMARK_MAIN();
The result is like:
> g++ benchmark.cc -lbenchmark -lpthread && ./a.out
2020-11-20T20:12:12+08:00
Running ./a.out
Run on (16 X 1796.56 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 512 KiB (x8)
L3 Unified 4096 KiB (x1)
Load Average: 0.29, 0.15, 0.10
------------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------------
copy_using_memcpy 2.44 ns 2.44 ns 282774223
copy_using_deref 1.77 ns 1.77 ns 389126375
In the original example, with only two fields, the time is roughly the same.
I can't think of any good reason to use memcpy()
rather than an assignment when copying a struct (as long as you don't need to do a deep copy or something involving the struct hack or a flexible array member, none of which apply in this case).
They have exactly the same semantics, and the assignment (a) likely gives the compiler more opportunities for optimization, and (b) has less risk of getting the size wrong.
Some very old C compilers probably didn't support struct assignment, but that's no longer a significant concern.
(There are additional reasons to prefer assignment in C++, but your question is about C.)
Incidentally, the parentheses in
(*pto) = (*pfrom);
are unnecessary; the unary *
binds tightly enough that this:
*pto = *pfrom;
is both correct and sufficiently clear to most readers.