memmove和memcpy有什么区别?

时间:2009-07-29 16:01:43

标签: c memcpy memmove

memmovememcpy之间有什么区别?您经常使用哪一个以及如何使用?

8 个答案:

答案 0 :(得分:148)

使用memcpy时,目标根本不能与源重叠。使用memmove即可。这意味着memmove可能会比memcpy略慢,因为它无法做出相同的假设。

例如,memcpy可能始终将地址从低位复制到高位。如果目标在源之后重叠,则表示在复制之前将覆盖某些地址。在这种情况下,memmove会检测到这一点并从另一个方向复制 - 从高到低。但是,检查这个并切换到另一个(可能效率较低)算法需要时间。

答案 1 :(得分:31)

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

答案 2 :(得分:22)

来自memcpy手册页。

  

memcpy()函数复制n个字节   从内存区域src到内存区域   DEST。内存区域不应该   交叠。如果是内存,请使用memmove(3)   区域重叠。

答案 3 :(得分:13)

memmove()memcpy()之间的主要区别在于memmove()使用缓冲区 - 临时内存 - 因此不存在重叠的风险。另一方面,memcpy()直接将数据从指向的位置复制到目标指向的位置。 (http://www.cplusplus.com/reference/cstring/memcpy/

请考虑以下示例:

  1. #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
    
  2. 但在本例中,结果将不相同:

    #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
    
  3. 这是因为&#34; memcpy()&#34;执行以下操作:

    1.  stackoverflow
    2.  stacksverflow
    3.  stacksterflow
    4.  stackstarflow
    5.  stackstacflow
    6.  stackstacklow
    7.  stackstacksow
    8.  stackstackstw
    

答案 4 :(得分:10)

一个处理重叠目的地而另一个不处理。

答案 5 :(得分:4)

假设您必须同时实现这两者,实现可能如下所示:

void memmove ( void * dst, const void * src, size_t count ) {
    if ((uintptr_t)src < (uintptr_t)dst) {
        // Copy from back to front

    } else if ((uintptr_t)dst < (uintptr_t)src) {
        // Copy from front to back
    }
}

void mempy ( void * dst, const void * src, size_t count ) {
    if ((uintptr_t)src != (uintptr_t)dst) {
        // Copy in any way you want
    }
}

这应该很好地解释了差异。 memmove总是以这样的方式进行复制,如果srcdst重叠,那么它仍然是安全的,而memcpy就像文档中所说的memcpy一样无关紧要memcpy 1}},两个内存区域不得重叠。

E.g。如果[---- src ----] [---- dst ---] 复制“从前到后”并且内存块按此对齐

src

然后从dst执行src复制第一个字节已经破坏了src的最后一个字节的内容,然后才复制它们。所以这里只能安全地复制“回到前面”。

现在交换dst[---- dst ----] [---- src ---]

src

在这种情况下,复制“从前到后”是唯一安全的,因为复制“返回前面”会在复制第一个字节时破坏其前面附近的memmove

你可能已经注意到上面的memcpy实现甚至没有测试它们是否确实重叠,它只是检查它们的相对位置,但仅此一项将使副本安全。由于memmove通常使用最快的方式来复制任何系统上的内存,void memmove ( void * dst, const void * src, size_t count ) { if ((uintptr_t)src < (uintptr_t)dst && (uintptr_t)src + count > (uintptr_t)dst) { // Copy from back to front } else if ((uintptr_t)dst < (uintptr_t)src && (uintptr_t)dst + count > (uintptr_t)src ) { // Copy from front to back } else { // They don't overlap for sure memcpy(dst, src, count); } } 通常实现为:

memcpy

有时,如果memmove始终复制“从前到后”或“从前到后”,memcpy也可能会在其中一个重叠案例中使用memcpymemcpy甚至可能以不同的方式复制,具体取决于数据的对齐方式和/或要复制的数据量,因此即使您测试了src在系统上的复制方式,也不能依赖于该测试结果。总是正确的。

在决定调用哪一个时,这对您意味着什么?

  1. 除非您确定dstmemmove不重叠,否则请致电src,因为它始终会产生正确的结果,并且通常与此一样快可能适用于您需要的复制案例。

  2. 如果您确定dstmemcpy没有重叠,请致电memmove因为您要求结果的哪一个无关紧要在这种情况下正常工作,但memcpy永远不会比memcpy快,如果你运气不好,它甚至可能会变慢,所以你只能赢得field1的召唤。

答案 6 :(得分:0)

有两种显而易见的方法可以实现mempcpy(void *dest, const void *src, size_t n)(忽略返回值):

  1. for (char *p=src, *q=dest;  n-->0;  ++p, ++q)
        *q=*p;
    
  2. char *p=src, *q=dest;
    while (n-->0)
        q[n]=p[n];
    
  3. 在第一个实现中,复制从低地址开始到高地址,在第二个实现中,从高到低。如果要复制的范围重叠(例如,滚动帧缓冲区的情况),则只有一个操作方向是正确的,另一个操作方向将覆盖随后将从中读取的位置。

    最简单的memmove()实现将测试dest<src(以某种平台相关的方式),并执行memcpy()的适当方向。

    用户代码当然不能这样做,因为即使在将srcdst投射到某个具体的指针类型之后,它们也不会(通常)指向相同的对象等因此无法进行比较。但是标准库可以具有足够的平台知识来执行这样的比较,而不会导致未定义的行为。

    请注意,在现实生活中,实现往往要复杂得多,以便从更大的传输(在对齐允许时)和/或良好的数据缓存利用率中获得最大性能。上面的代码只是为了尽可能简单。

答案 7 :(得分:0)

memmove可以处理重叠的源和目标区域,而memcpy则不能。在这两者中,memcpy效率更高。所以,如果可以,最好使用memcpy。

参考文献:https://www.youtube.com/watch?v=Yr1YnOVG-4g Jerry Cain博士,(斯坦福大学入门系统讲座 - 7)时间:36:00