What is the difference between memmove and memcpy?

前端 未结 9 1709
Happy的楠姐
Happy的楠姐 2020-11-28 02:13

What is the difference between memmove and memcpy? Which one do you usually use and how?

相关标签:
9条回答
  • 2020-11-28 02:42

    Assuming you would have to implement both, the implementation could look like that:

    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 memcpy ( void * dst, const void * src, size_t count ) {
        if ((uintptr_t)src != (uintptr_t)dst) {
            // Copy in any way you want
        }
    }
    

    And this should pretty well explain the difference. memmove always copies in such a way, that it is still safe if src and dst overlap, whereas memcpy just doesn't care as the documentation says when using memcpy, the two memory areas must not overlap.

    E.g. if memcpy copies "front to back" and the memory blocks are aligned as this

    [---- src ----]
                [---- dst ---]
    

    copying the first byte of src to dst already destroys the content of the last bytes of src before these have been copied. Only copying "back to front" will lead to correct results.

    Now swap src and dst:

    [---- dst ----]
                [---- src ---]
    

    In that case it's only safe to copy "front to back" as copying "back to front" would destroy src near its front already when copying the first byte.

    You may have noticed that the memmove implementation above doesn't even test if they actually do overlap, it just checks their relative positions, but that alone will make the copy safe. As memcpy usually uses the fastest way possible to copy memory on any system, memmove is usually rather implemented as:

    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);
        }
    }
    

    Sometimes, if memcpy always copies "front to back" or "back to front", memmove may also use memcpy in one of the overlapping cases but memcpy may even copy in a different way depending on how the data is aligned and/or how much data is to be copied, so even if you tested how memcpy copies on your system, you cannot rely on that test result to be always correct.

    What does that mean for you when deciding which one to call?

    1. Unless you know for sure that src and dst don't overlap, call memmove as it will always lead to correct results and is usually as fast as that is possible for the copy case you require.

    2. If you know for sure that src and dst don't overlap, call memcpy as it won't matter which one you call for the result, both will work correctly in that case, but memmove will never be faster than memcpy and if you are unlucky, it may even be slower, so you can only win calling memcpy.

    0 讨论(0)
  • 2020-11-28 02:42

    One handles overlapping destinations the other doesn't.

    0 讨论(0)
  • 2020-11-28 02:52

    From the memcpy man page.

    The memcpy() function copies n bytes from memory area src to memory area dest. The memory areas should not overlap. Use memmove(3) if the memory areas do overlap.

    0 讨论(0)
提交回复
热议问题