Понимание исходного кода 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
делает это за одну итерацию, копируя слово сразу.