Предполагая, что вам придется реализовать оба варианта, реализация может выглядеть так:
void memmove ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src < (uintptr_t)dst) {
// Copy from back to front
} else if ((uintptr_t)dst < (uintptr_t)src) {
// Copy from front to back
}
}
void mempy ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src != (uintptr_t)dst) {
// Copy in any way you want
}
}
И это должно хорошо объяснить разницу. memmove
всегда копирует таким образом, что все еще безопасно, если src
и dst
перекрываются, тогда как memcpy
просто не волнует, как сказано в документации при использовании memcpy
, две области памяти не должен перекрываться.
например. если memcpy
копирует "спереди назад" и блоки памяти выровнены как это
[---- src ----]
[---- dst ---]
Затем копирование первого байта из src
do dst
уже уничтожает содержимое последних байтов src
до того, как они были скопированы. Так что здесь можно копировать только «назад на фронт».
Теперь поменяйте местами src
и dst
:
[---- dst ----]
[---- src ---]
В этом случае безопаснее копировать «спереди назад», поскольку копирование «спереди назад» уничтожит src
около его фронта уже при копировании первого байта.
Возможно, вы заметили, что реализация memmove
, описанная выше, даже не проверяет, действительно ли они перекрываются, она просто проверяет их относительные позиции, но только это сделает копию безопасной. Поскольку memcpy
обычно использует самый быстрый способ копирования памяти в любой системе, memmove
обычно реализуется как:
void memmove ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src < (uintptr_t)dst
&& (uintptr_t)src + count > (uintptr_t)dst) {
// Copy from back to front
} else if ((uintptr_t)dst < (uintptr_t)src
&& (uintptr_t)dst + count > (uintptr_t)src
) {
// Copy from front to back
} else {
// They don't overlap for sure
memcpy(dst, src, count);
}
}
Иногда, если memcpy
всегда копирует «спереди назад» или «спереди назад», memmove
может также использовать memcpy
в одном из перекрывающихся случаев, но memcpy
может даже копировать по-другому в зависимости от о том, как данные выровнены и / или сколько данных должно быть скопировано, поэтому даже если вы проверяли, как memcpy
копирует в вашей системе, вы не можете полагаться на то, что результаты теста всегда будут правильными.
Что это значит для вас, когда вы решаете, кому позвонить?
Если вы точно не знаете, что src
и dst
не перекрываются, позвоните по номеру memmove
, так как это всегда приведет к правильным результатам и обычно настолько быстро, насколько это возможно для случая копирования, который вы требуется.
Если вы точно знаете, что src
и dst
не перекрываются, наберите memcpy
, так как не имеет значения, какой из них вы вызываете для результата, оба будут работать правильно в этом случае, но memmove
никогда не будет быстрее, чем memcpy
, и, если вам не повезет, он может быть даже медленнее, поэтому вы можете выиграть, только позвонив memcpy
.