Понимание исходного кода memcpy()

00018 void *memcpy(void *dst, const void *src, size_t len)
00019 {
00020         size_t i;
00021 
00022         /*
00023          * memcpy does not support overlapping buffers, so always do it
00024          * forwards. (Don't change this without adjusting memmove.)
00025          *
00026          * For speedy copying, optimize the common case where both pointers
00027          * and the length are word-aligned, and copy word-at-a-time instead
00028          * of byte-at-a-time. Otherwise, copy by bytes.
00029          *
00030          * The alignment logic below should be portable. We rely on
00031          * the compiler to be reasonably intelligent about optimizing
00032          * the divides and modulos out. Fortunately, it is.
00033          */
00034 
00035         if ((uintptr_t)dst % sizeof(long) == 0 &&
00036             (uintptr_t)src % sizeof(long) == 0 &&
00037             len % sizeof(long) == 0) {
00038 
00039                 long *d = dst;
00040                 const long *s = src;
00041 
00042                 for (i=0; i<len/sizeof(long); i++) {
00043                         d[i] = s[i];
00044                 }
00045         }
00046         else {
00047                 char *d = dst;
00048                 const char *s = src;
00049 
00050                 for (i=0; i<len; i++) {
00051                         d[i] = s[i];
00052                 }
00053         }
00054 
00055         return dst;
00056 }

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

Я не мог понять if часть, которую они делают для целых чисел — i < len/sizeof(long). Зачем нужен этот расчет?

Ответ 1

Я не мог понять, что они делают для целых чисел. я < Len/SizeOf (длинный). Зачем нужен этот расчет?

Поскольку они копируют слова, а не отдельные байты, в этом случае (как отмечается в комментарии, это оптимизация - для этого требуется меньше итераций, а ЦП может обрабатывать данные с выравниванием слов более эффективно).

len - это количество байтов для копирования, а sizeof(long) - размер одного слова, поэтому количество элементов для копирования (означает, циклические итерации для выполнения) len / sizeof(long).

Ответ 2

чтобы понять, как он отличается от использования цикла. Но я не мог разница использования цикла, а не memcpy, поскольку memcpy использует цикл снова внутренне, чтобы скопировать

Ну, тогда он использует цикл. Возможно, другие реализации libc этого не делают. В любом случае, что проблема/вопрос, если он использует цикл? Также, как вы видите, это больше, чем цикл: он проверяет выравнивание и выполняет различный цикл в зависимости от выравнивания.

Я не мог понять, что они делают для целых чисел. я < Len/SizeOf (длинный). Зачем нужен этот расчет?

Это проверка выравнивания слов памяти. Если адресаты назначения и адреса источника выравниваются по словам, а длина копии кратна размеру слова, то она выполняет выровненную копию по слову (long), которая быстрее, чем использование байтов (char), не только из-за размера, но также и потому, что большинство архитектур делают копии с выравниванием по порядку намного быстрее.

Ответ 3

len%sizeof(long) проверяет, не пытаетесь ли вы копировать полные длины, а не часть long.

00035    if ((uintptr_t)dst % sizeof(long) == 0 &&
00036             (uintptr_t)src % sizeof(long) == 0 &&
00037             len % sizeof(long) == 0) {
00038 
00039                 long *d = dst;
00040                 const long *s = src;
00041 
00042                 for (i=0; i<len/sizeof(long); i++) {
00043                         d[i] = s[i];
00044                 }

проверяет выравнивание и если true, копирует быстро (sizeof(long) байты за раз).

00046    else {
00047                 char *d = dst;
00048                 const char *s = src;
00049 
00050                 for (i=0; i<len; i++) {
00051                         d[i] = s[i];
00052                 }
00053    }

это для неправильно выровненных массивов (медленная копия (по 1 байт за раз))

Ответ 4

for (i=0; i<len/sizeof(long); i++) {
    d[i] = s[i];
}

В этом цикле for каждый раз, когда скопирован a long, для копирования требуется общий размер len, поэтому ему нужно i<len/sizeof(long) в качестве условия для завершения цикла.

Ответ 5

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

Цикл (операторы управления) является одним из основных элементов, примыкающих к if (решениям) и нескольким другим подобным вещам. Поэтому вопрос здесь не в том, в чем разница между обычным циклом и использованием memcpy.

memcpy только помогает вашей задаче, предоставляя вам готовый вызов API, вместо того, чтобы писать 20 строк кода для мелочей. Если вы хотите, вы можете написать свой собственный код, чтобы предоставить вам ту же функциональность.

Второй момент, как уже указывалось ранее, заключается в том, что он обеспечивает оптимизацию между long типом данных и другими типами. Потому что в long это копирование блока данных сразу, что мы называем словом, вместо того, чтобы копировать байты за байтом, что заняло бы больше времени. В случае long, та же самая операция, для выполнения которой потребуется 8 итераций, memcpy делает это за одну итерацию, копируя слово сразу.