C语言 memcpy() 与 memmove()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4415910/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
memcpy() vs memmove()
提问by user534785
I am trying to understand the difference between memcpy()and memmove(), and I have read the text that memcpy()doesn't take care of the overlapping source and destination whereas memmove()does.
我想明白之间的差别memcpy(),并memmove()和我有阅读的文本memcpy(),而没有照顾重叠源和目的地memmove()一样。
However, when I execute these two functions on overlapping memory blocks, they both give the same result. For instance, take the following MSDN example on the memmove()help page:-
但是,当我在重叠的内存块上执行这两个函数时,它们都给出了相同的结果。例如,以memmove()帮助页面上的以下 MSDN 示例为例:-
Is there a better example to understand the drawbacks of memcpyand how memmovesolves it?
有没有更好的例子来理解它的缺点memcpy以及如何memmove解决它?
// crt_memcpy.c
// Illustrate overlapping copy: memmove always handles it correctly; memcpy may handle
// it correctly.
#include <memory.h>
#include <string.h>
#include <stdio.h>
char str1[7] = "aabbcc";
int main( void )
{
printf( "The string: %s\n", str1 );
memcpy( str1 + 2, str1, 4 );
printf( "New string: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "aabbcc" ); // reset string
printf( "The string: %s\n", str1 );
memmove( str1 + 2, str1, 4 );
printf( "New string: %s\n", str1 );
}
Output:
输出:
The string: aabbcc
New string: aaaabb
The string: aabbcc
New string: aaaabb
采纳答案by developmentalinsanity
I'm not entirely surprised that your example exhibits no strange behaviour. Try copying str1to str1+2instead and see what happens then. (May not actually make a difference, depends on compiler/libraries.)
我并不完全惊讶你的例子没有表现出奇怪的行为。尝试复制str1到str1+2,然后看看会发生什么。(实际上可能没有什么不同,取决于编译器/库。)
In general, memcpy is implemented in a simple (but fast) manner. Simplistically, it just loops over the data (in order), copying from one location to the other. This can result in the source being overwritten while it's being read.
通常,memcpy 以简单(但快速)的方式实现。简单地说,它只是遍历数据(按顺序),从一个位置复制到另一个位置。这可能导致源在读取时被覆盖。
Memmove does more work to ensure it handles the overlap correctly.
Memmove 做了更多的工作来确保它正确处理重叠。
EDIT:
编辑:
(Unfortunately, I can't find decent examples, but these will do). Contrast the memcpyand memmoveimplementations shown here. memcpy just loops, while memmove performs a test to determine which direction to loop in to avoid corrupting the data. These implementations are rather simple. Most high-performance implementations are more complicated (involving copying word-size blocks at a time rather than bytes).
(不幸的是,我找不到像样的例子,但这些都可以)。对比此处显示的memcpy和memmove实现。memcpy 只是循环,而 memmove 执行测试以确定循环的方向以避免损坏数据。这些实现相当简单。大多数高性能实现更复杂(涉及一次复制字大小的块而不是字节)。
回答by rxantos
The memory in memcpycannotoverlap or you risk undefined behaviour, while the memory in memmovecan overlap.
内存memcpy不能重叠,否则你会冒未定义行为的风险,而内存memmove可以重叠。
char a[16];
char b[16];
memcpy(a,b,16); // valid
memmove(a,b,16); // Also valid, but slower than memcpy.
memcpy(&a[0], &a[1],10); // Not valid since it overlaps.
memmove(&a[0], &a[1],10); // valid.
Some implementations of memcpy might still work for overlapping inputs but you cannot count of that behaviour. While memmove must allow for overlapping.
memcpy 的某些实现可能仍然适用于重叠输入,但您无法计算这种行为。而 memmove 必须允许重叠。
回答by Billy ONeal
Just because memcpydoesn't have to deal with overlapping regions, doesn't mean it doesn't deal with them correctly. The call with overlapping regions produces undefined behavior. Undefined behavior can work entirely as you expect on one platform; that doesn't mean it's correct or valid.
仅仅因为memcpy不必处理重叠区域,并不意味着它没有正确处理它们。具有重叠区域的调用会产生未定义的行为。未定义的行为可以在一个平台上完全按照您的预期工作;这并不意味着它是正确或有效的。
回答by Neilvert Noval
Both memcpy and memove do similar things.
memcpy 和 memove 都做类似的事情。
But to sight out one difference:
但要注意一个区别:
#include <memory.h>
#include <string.h>
#include <stdio.h>
char str1[7] = "abcdef";
int main()
{
printf( "The string: %s\n", str1 );
memcpy( (str1+6), str1, 10 );
printf( "New string: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "aabbcc" ); // reset string
printf("\nstr1: %s\n", str1);
printf( "The string: %s\n", str1 );
memmove( (str1+6), str1, 10 );
printf( "New string: %s\n", str1 );
}
gives:
给出:
The string: abcdef
New string: abcdefabcdefabcd
The string: abcdef
New string: abcdefabcdef
回答by huubby
Your demo didn't expose memcpy drawbacks because of "bad" compiler, it does you a favor in Debug version. A release version, however, gives you the same output, but because of optimization.
你的演示没有因为“坏”编译器而暴露 memcpy 的缺点,它在调试版本中对你有帮助。然而,发布版本为您提供相同的输出,但由于优化。
memcpy(str1 + 2, str1, 4);
00241013 mov eax,dword ptr [str1 (243018h)] // load 4 bytes from source string
printf("New string: %s\n", str1);
00241018 push offset str1 (243018h)
0024101D push offset string "New string: %s\n" (242104h)
00241022 mov dword ptr [str1+2 (24301Ah)],eax // put 4 bytes to destination
00241027 call esi
The register %eaxhere plays as a temporary storage, which "elegantly" fixes overlap issue.
%eax这里的寄存器充当临时存储,它“优雅地”解决了重叠问题。
The drawback emerges when copying 6 bytes, well, at least part of it.
复制 6 个字节时会出现缺点,好吧,至少是其中的一部分。
char str1[9] = "aabbccdd";
int main( void )
{
printf("The string: %s\n", str1);
memcpy(str1 + 2, str1, 6);
printf("New string: %s\n", str1);
strcpy_s(str1, sizeof(str1), "aabbccdd"); // reset string
printf("The string: %s\n", str1);
memmove(str1 + 2, str1, 6);
printf("New string: %s\n", str1);
}
Output:
输出:
The string: aabbccdd
New string: aaaabbbb
The string: aabbccdd
New string: aaaabbcc
Looks weird, it's caused by optimization, too.
看起来很奇怪,它也是由优化引起的。
memcpy(str1 + 2, str1, 6);
00341013 mov eax,dword ptr [str1 (343018h)]
00341018 mov dword ptr [str1+2 (34301Ah)],eax // put 4 bytes to destination, earlier than the above example
0034101D mov cx,word ptr [str1+4 (34301Ch)] // HA, new register! Holding a word, which is exactly the left 2 bytes (after 4 bytes loaded to %eax)
printf("New string: %s\n", str1);
00341024 push offset str1 (343018h)
00341029 push offset string "New string: %s\n" (342104h)
0034102E mov word ptr [str1+6 (34301Eh)],cx // Again, pulling the stored word back from the new register
00341035 call esi
This is why I always choose memmovewhen trying to copy 2 overlapped memory blocks.
这就是为什么我memmove在尝试复制 2 个重叠的内存块时总是选择的原因。
回答by R srinivas reddy
The difference between memcpyand memmoveis that
memcpy和之间的区别memmove在于
in
memmove, the source memory of specified size is copied into buffer and then moved to destination. So if the memory is overlapping, there are no side effects.in case of
memcpy(), there is no extra buffer taken for source memory. The copying is done directly on the memory so that when there is memory overlap, we get unexpected results.
在 中
memmove,指定大小的源内存被复制到缓冲区,然后移动到目标。因此,如果内存重叠,则没有副作用。在 的情况下
memcpy(),不会为源内存占用额外的缓冲区。复制直接在内存上完成,这样当内存重叠时,我们会得到意想不到的结果。
These can be observed by the following code:
这些可以通过以下代码观察:
//include string.h, stdio.h, stdlib.h
int main(){
char a[]="hare rama hare rama";
char b[]="hare rama hare rama";
memmove(a+5,a,20);
puts(a);
memcpy(b+5,b,20);
puts(b);
}
Output is:
输出是:
hare hare rama hare rama
hare hare hare hare hare hare rama hare rama
回答by Ог?ен Шоба?и?
As already pointed out in other answers, memmoveis more sophisticated than memcpysuch that it accounts for memory overlaps. The result of memmove is defined as if the srcwas copied into a buffer and then buffer copied into dst. This does NOT mean that the actual implementation uses any buffer, but probably does some pointer arithmetic.
正如在其他答案中已经指出的那样,memmove比memcpy考虑内存重叠更复杂。memmove 的结果被定义为好像将src复制到缓冲区中,然后将缓冲区复制到dst. 这并不意味着实际实现使用任何缓冲区,但可能会进行一些指针运算。
回答by singingsingh
The code given in the links http://clc-wiki.net/wiki/memcpyfor memcpy seems to confuse me a bit, as it does not give the same output when I implemented it using the below example.
链接http://clc-wiki.net/wiki/memcpyfor memcpy 中给出的代码似乎让我有点困惑,因为当我使用下面的示例实现它时,它没有给出相同的输出。
#include <memory.h>
#include <string.h>
#include <stdio.h>
char str1[11] = "abcdefghij";
void *memcpyCustom(void *dest, const void *src, size_t n)
{
char *dp = (char *)dest;
const char *sp = (char *)src;
while (n--)
*dp++ = *sp++;
return dest;
}
void *memmoveCustom(void *dest, const void *src, size_t n)
{
unsigned char *pd = (unsigned char *)dest;
const unsigned char *ps = (unsigned char *)src;
if ( ps < pd )
for (pd += n, ps += n; n--;)
*--pd = *--ps;
else
while(n--)
*pd++ = *ps++;
return dest;
}
int main( void )
{
printf( "The string: %s\n", str1 );
memcpy( str1 + 1, str1, 9 );
printf( "Actual memcpy output: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "abcdefghij" ); // reset string
memcpyCustom( str1 + 1, str1, 9 );
printf( "Implemented memcpy output: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "abcdefghij" ); // reset string
memmoveCustom( str1 + 1, str1, 9 );
printf( "Implemented memmove output: %s\n", str1 );
getchar();
}
Output :
输出 :
The string: abcdefghij
Actual memcpy output: aabcdefghi
Implemented memcpy output: aaaaaaaaaa
Implemented memmove output: aabcdefghi
But you can now understand why memmovewill take care of overlapping issue.
但是您现在可以理解为什么memmove会处理重叠问题。
回答by rockeet
compiler could optimize memcpy, for example:
编译器可以优化 memcpy,例如:
int x;
memcpy(&x, some_pointer, sizeof(int));
This memcpy may be optimized as: x = *(int*)some_pointer;
这个 memcpy 可以优化为: x = *(int*)some_pointer;
回答by Pratik Panchal
I have tried to run same program using eclipse and it shows clear difference between memcpyand memmove. memcpy()doesn't care about overlapping of memory location which results in corruption of data, while memmove()will copy data to temporary variable first and then copy into actual memory location.
我尝试使用 eclipse 运行相同的程序,它显示了memcpy和之间的明显区别memmove。memcpy()不关心导致数据损坏的内存位置重叠,同时memmove()将数据先复制到临时变量,然后再复制到实际内存位置。
While trying to copy data from location str1to str1+2, output of memcpyis "aaaaaa". The question would be how?
memcpy()will copy one byte at a time from left to right. As shown in your program "aabbcc" then
all copying will take place as below,
尝试将数据从位置复制str1到 时str1+2,输出memcpy为“ aaaaaa”。问题是如何?
memcpy()将从左到右一次复制一个字节。如您的程序“ aabbcc”所示,所有复制将如下进行,
aabbcc -> aaabccaaabcc -> aaaaccaaaacc -> aaaaacaaaaac -> aaaaaa
aabbcc -> aaabccaaabcc -> aaaaccaaaacc -> aaaaacaaaaac -> aaaaaa
memmove()will copy data to temporary variable first and then copy to actual memory location.
memmove()将首先将数据复制到临时变量,然后再复制到实际内存位置。
aabbcc(actual) -> aabbcc(temp)aabbcc(temp) -> aaabcc(act)aabbcc(temp) -> aaaacc(act)aabbcc(temp) -> aaaabc(act)aabbcc(temp) -> aaaabb(act)
aabbcc(actual) -> aabbcc(temp)aabbcc(temp) -> aaabcc(act)aabbcc(temp) -> aaaacc(act)aabbcc(temp) -> aaaabc(act)aabbcc(temp) -> aaaabb(act)
Output is
输出是
memcpy: aaaaaa
memcpy: aaaaaa
memmove: aaaabb
memmove: aaaabb

