memmove和memcpy有什么区别?
memmove
和memcpy
什么区别? 你通常使用哪一个?
使用memcpy
,目标不能与源重叠。 随着移动它可以。 这意味着memmove
可能会比memcpy
慢一点,因为它不能做出相同的假设。
例如, memcpy
可能总是将地址从低到高复制。 如果目标在源之后重叠,这意味着某些地址在复制之前将被覆盖。 memmove
会检测到这一点,并在另一个方向复制 – 在这种情况下,从高到低。 但是,检查这个并切换到另一个(可能效率较低)的algorithm需要时间。
memmove
可以处理重叠的内存, memcpy
不能。
考虑
char[] str = "foo-bar"; memcpy(&str[3],&str[4],4); //might blow up
显然源和目的地重叠,我们用“bar”覆盖“-bar”。 如果源和目标重叠,则使用memcpy
是未定义的行为,所以在这种情况下,我们需要memmove
。
memmove(&str[3],&str[4],4); //fine
从memcpy手册页。
memcpy()函数从存储区src复制n个字节到存储区dest。 内存区域不应该重叠。 如果内存区域重叠,请使用memmove (3)。
一个处理重叠的目的地,另一个不处理。
memmove()
和memcpy()
之间的主要区别是在memmove()
了缓冲区 – 临时内存 – 所以没有重叠的风险。 另一方面, memcpy()
直接将数据从源指向的位置复制到目标指向的位置。 ( http://www.cplusplus.com/reference/cstring/memcpy/ )
考虑下面的例子:
-
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *first, *second; first = string; second = string; puts(string); memcpy(first+5, first, 5); puts(first); memmove(second+5, second, 5); puts(second); return 0; }
如你所料,这将打印出来:
stackoverflow stackstacklow stackstacklow
-
但在这个例子中,结果将不一样:
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *third, *fourth; third = string; fourth = string; puts(string); memcpy(third+5, third, 7); puts(third); memmove(fourth+5, fourth, 7); puts(fourth); return 0; }
输出:
stackoverflow stackstackovw stackstackstw
这是因为“memcpy()”执行以下操作:
1. stackoverflow 2. stacksverflow 3. stacksterflow 4. stackstarflow 5. stackstacflow 6. stackstacklow 7. stackstacksow 8. stackstackstw
简单地从ISO / IEC:9899标准就可以很好地描述。
7.21.2.1 memcpy函数
[…]
2 memcpy函数将s2指向的对象中的n个字符复制到s1指向的对象中。 如果在重叠的对象之间进行复制,则行为是不确定的。
和
7.21.2.2移动function
[…]
2 memmove函数将s2指向的对象中的n个字符复制到s1指向的对象中。 复制的过程与从s2指向的对象中的n个字符首先复制到n个字符的临时数组中,这些字符不与 s1和s2指向的对象重叠 ,然后将临时数组中的n个字符复制到s1指向的对象。
我通常根据问题select哪一个取决于我需要的function。
在纯文本中, memcpy()
不允许s1
和s2
重叠,而memmove()
却是这样。
我试着运行上面的代码:主要原因我想知道memcpy
和memmove
的区别。
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *third, *fourth; third = string; fourth = string; puts(string); memcpy(third+5, third, 7); puts(third); memmove(fourth+5, fourth, 7); puts(fourth); return 0; }
给出下面的输出
stackoverflow stackstackovw stackstackstw
现在我用memcpy
replace了memmove
,并得到了相同的输出
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *first, *second; first = string; second = string; puts(string); memcpy(first+5, first,7); puts(first); memcpy(second+5, second, 7); puts(second); return 0; }
输出:
stackoverflow stackstackovw stackstackstw
char string [] =“stackoverflow”;
char *first, *second; first = string; second = string; puts(string);
o / p – stackoverflow
memcpy(first+5, first,7); puts(first);
这里有7个由第二个指向的字符,即“stackov”粘贴在+5位置
o / p – stackstackovw
memcpy(second+5, second, 7); puts(second);
这里inputstring是“stackstackovw”,第二个字符(即“stackst”)被复制到一个缓冲区,然后粘贴到+5
o / p – stackstackstw
0 —– + 5
堆栈栈
有两种明显的方法来实现mempcpy(void *dest, const void *src, size_t n)
(忽略返回值):
-
for (char *p=src, *q=dest; n-->0; ++p, ++q) *q=*p;
-
char *p=src, *q=dest; while (n-->0) q[n]=p[n];
在第一个实现中,拷贝从低地址到高地址,而在第二个地址从高到低。 如果要复制的范围重叠(例如,滚动帧缓冲区的情况),则只有一个操作方向是正确的,另一个将覆盖随后将读取的位置。
一个简单的memmove()
实现将testingdest<src
(以某种依赖于平台的方式),并执行memcpy()
的相应方向。
用户代码当然不能这样做,因为即使在将src
和dst
为某个具体的指针types之后,它们也不会(通常)指向同一个对象,因此无法进行比较。 但是标准库可以有足够的平台知识来执行这样的比较,而不会导致未定义的行为。
请注意,在现实生活中,实现往往要复杂得多,以便从较大的传输(在alignment允许时)和/或良好的数据高速caching利用率中获得最大的性能。 上面的代码只是为了尽可能简单地说明问题。
memmove可以处理重叠的源和目标区域,而memcpy不能。 其中memcpy更有效率。 所以,如果可以的话,最好使用memcpy。
参考: https : //www.youtube.com/watch?v= Yr1YnOVG-4g杰里·凯恩博士(斯坦福大学介绍系统讲座 – 7)时间:36:00
以前的答案已经很好地说明了技术差异。 还应注意实际的差异:
Memcpy将需要大约两倍的内存来执行相同的任务,但是memmove可能比memcpy花费更长的时间。
例:
假设你在内存中有100个项目的列表,占用100MB的内存。 你想放弃第一个项目,所以你只有99。
Memcpy将需要原始的100 MB和99个新的99个项目的额外的99 MB。 总共需要大约199 MB来执行操作,但应该非常快。
Memmove,在最糟糕的情况下将需要原来的100 MB,并将每次移动每个项目1内存地址。 这只需要原来的100MB,但是会比Memcpy慢得多。
当然,创build一个指向列表中第二项的新指针将达到同样的效果,即从列表中删除第一项,但是该示例很好地显示了memcpy和memmove之间的差异。
– 编辑,以帮助澄清我的快乐回答 –
是的,memcpy()和memmove()的实现在内存使用方面可能没有区别(我真的不知道),但是如何使用它们将极大地影响程序的内存使用。 这就是我的意思是memcpy()和memmove()的实际区别。
int SIZE = 100; Item *ptr_item = (Item *) malloc(size_of(Item) * SIZE); Item *ptr_src_item = ptr_item + 1; Item *ptr_dst_item = ptr_item; memmove(ptr_dst_item, ptr_src_item, SIZE - 1);
这会创build你的第一个项目丢失的项目列表。 这基本上不需要为程序分配原始ptr_item内存块的内存。 你不能这样做使用memcpy()…如果你这样做,你的程序将需要分配大约两倍的内存。
int SIZE = 100; Item *ptr_src_item = (Item *) malloc(size_of(Item) * SIZE); Item *ptr_dst_item = (Item *) malloc(size_of(Item) * (SIZE - 1)); memcpy(ptr_dst_item, ptr_src_item, SIZE - 1);
在第二个代码块中,程序需要的内存是第一个块的两倍。 但是,第二块应该比第一块块快得多,尤其是在SIZE增加的情况下。
这就是我试图解释两者之间的实际差异……但也许我错了呢?