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)
。为什么要进行此计算?
答案 0 :(得分:14)
我无法理解他们是否为整数所做的部分。我&lt; LEN /的sizeof(长)。为什么要进行此计算?
因为它们是复制单词,而不是单个字节,在这种情况下(正如评论所说,它是一种优化 - 它需要更少的迭代,CPU可以更有效地处理字对齐的数据)。
len
是要复制的字节数,sizeof(long)
是单个字的大小,因此要素数量为copy(表示要执行的循环迭代)是len / sizeof(long)
。
答案 1 :(得分:6)
了解它与使用循环的不同之处。但我不能 使用循环而不是memcpy的区别,因为memcpy使用循环 再次在内部复制
然后它使用循环。也许libc的其他实现不会那样做。无论如何,如果它确实使用了循环,那么问题/问题是什么?另外,正如您所看到的那样,它不仅仅是一个循环:它会检查对齐并根据对齐方式执行不同类型的循环。
我无法理解他们是否为整数所做的部分。我&lt; LEN /的sizeof(长)。为什么要进行此计算?
这是检查内存字对齐。如果目标和源地址是字对齐的,并且长度副本是字大小的倍数,则它按字(long
)执行对齐复制,这比使用字节(char
更快),不仅因为大小,而且因为大多数架构更快地进行字对齐复制。
答案 2 :(得分:5)
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个字节))
答案 3 :(得分:4)
for (i=0; i<len/sizeof(long); i++) {
d[i] = s[i];
}
在这个for循环中,每次复制long
时,都要复制len
的总大小,这就是它需要i<len/sizeof(long)
作为终止循环的条件的原因。
答案 4 :(得分:0)
我只是通过
memcpy
的实现来了解它与使用循环的不同之处。但是我看不到使用循环而不是memcpy之间有什么区别,因为memcpy
再次在内部使用循环进行复制。
循环(控制语句)是与if(决策语句)相邻的基本元素之一,而其他几乎没有这样的东西。因此,这里的问题不是关于普通循环和使用memcpy
之间的区别。
memcpy
可以通过为您提供随时可用的API调用来帮助您完成任务,而不是让您为琐碎的事情编写20行代码。如果愿意,您可以选择编写自己的代码来为您提供相同的功能。
前面已经指出的第二点是,它在long
数据类型和其他类型之间提供了优化。因为在long
中,它是一次复制一个数据块,这就是我们所说的单词,而不是逐字节复制,这会花费更长的时间。如果执行的操作很长,则需要进行8次迭代才能完成 ,memcpy
一次复制一次单词即可完成一次迭代。 >
答案 5 :(得分:0)
好像您看到了memcpy的汇编代码,它表明在32位系统中,每个寄存器都是32位,它一次可以存储4个字节,如果仅在32位寄存器中复制一个字节,则CPU需要额外的指令周期。
如果len / count是4的倍数,我们可以在一个周期内复制4个字节
MOV FROM, R2
MOV TO, R3
MOV R2, R4
ADD LEN, R4
CP: MOV (R2+), (R3+) ; "(Rx+)" means "*Rx++" in C
CMP R2, R4
BNE CP