Почему Linux memmove() реализован так, как он есть?

Из man-страницы Linux для memmove (3)

Функция memmove() копирует n байтов из области памяти src в область памяти dest. Области памяти могут перекрываться: копирование происходит, как если бы байты в src были сначала копируется во временный массив, который не перекрывает src или dest, а байты затем копируются из временного массива в dest.

Вместо выделения временного массива и копирования значений дважды мы могли бы просто сделать следующее:

void *my_memmove(void *dest, const void *src, size_t n) {
  signed char operation;
  size_t end;
  size_t current;

  if(dest != src) {
    if(dest < src) {
      operation = 1;
      current = 0;
      end = n;
    } else {
      operation = -1;
      current = n - 1;
      end = -1;
    }

    for( ; current != end; current += operation) {
      *(((unsigned char*)dest) + current) = *(((unsigned char*)src) + current);
    }
  }
  return dest;
}

В этой реализации мы просто заботимся о позиции, где мы начинаем копировать.

Есть ли недостаток в моей реализации?

Примечание. Я не буду использовать свою реализацию. Мне просто интересно.

Ответ 1

Вы можете посмотреть какой-нибудь исходный код memmove здесь, здесь, здесь, и здесь.

Что вы заметите, так это то, что они фактически не создают временный массив. Страницы руководства написаны, чтобы помочь вам понять, что он делает логически, а не на самом деле. Следовательно, они говорят "как бы".

Что memmove() действительно делает, это копировать байты от src до dest, и он копирует вперед, если dest < src (что по сути то же самое, что и memcpy), и наоборот в противном случае.

Разница между memcpy и memmove заключается в том, что memcpy слепо копирует вперед - вот почему dest и src не должны перекрываться. Но memmove берет на себя обязательство гарантировать, что перекрытие не испортит конечный результат.