Почему 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
берет на себя обязательство гарантировать, что перекрытие не испортит конечный результат.