Существует, по крайней мере, неявная ветвь для копирования вперед или назад для memmove()
, если компилятор не может сделать вывод, что перекрытие невозможно. Это означает, что без возможности оптимизации в пользу memcpy()
, memmove()
по меньшей мере медленнее одной ветвью, а любое дополнительное пространство занято встроенными инструкциями для обработки каждого случая (если встраивание возможно).
Считывание кода eglibc-2.11.1
для memcpy()
и memmove()
подтверждает это как подозрение. Кроме того, нет возможности копирования страниц при обратном копировании, существенное ускорение доступно только в том случае, если нет шансов для наложения.
В итоге это означает: если вы можете гарантировать, что регионы не перекрываются, то выбор memcpy()
over memmove()
позволяет избежать ветвления. Если источник и назначение содержат соответствующие области, выровненные по размеру страницы и по размеру страницы, и не перекрываются, некоторые архитектуры могут использовать аппаратно ускоренные копии для этих областей, независимо от того, вызвали ли вы memmove()
или memcpy()
.
Update0
На самом деле есть еще одно отличие от предположений и наблюдений, которые я перечислил выше. Начиная с C99, для двух функций существуют следующие прототипы:
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
void *memmove(void * s1, const void * s2, size_t n);
Из-за возможности предположить, что 2 указателя s1
и s2
не указывают на перекрывающуюся память, простые реализации C memcpy
могут использовать это для генерации более эффективного кода без обращения к ассемблеру, см. здесь для более. Я уверен, что memmove
может сделать это, однако потребуются дополнительные проверки сверх тех, которые я видел в eglibc
, что означает, что затраты производительности могут быть немного больше, чем одна ветвь для реализаций этих функций на Си.