memcpy與memmove的區(qū)別

memcpy和memmove都是C語言的庫函數(shù),相比于strcpy和strncpy只能拷貝字符串?dāng)?shù)組,memcpy與memmove可以拷貝其它類型的數(shù)組,但是為什么要同時(shí)提供兩種方法呢?本文主要就是介紹這兩個(gè)函數(shù)的區(qū)別。

首先來看函數(shù)原型:

void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);

這兩個(gè)函數(shù)都是將s2指向位置的n字節(jié)數(shù)據(jù)拷貝到s1指向的位置,區(qū)別就在于關(guān)鍵字restrict, memcpy假定兩塊內(nèi)存區(qū)域沒有數(shù)據(jù)重疊,而memmove沒有這個(gè)前提條件。如果復(fù)制的兩個(gè)區(qū)域存在重疊時(shí)使用memcpy,其結(jié)果是不可預(yù)知的,有可能成功也有可能失敗的,所以如果使用了memcpy,程序員自身必須確保兩塊內(nèi)存沒有重疊部分。

我們來看一組示例:

正常的拷貝

正常情況下,即使內(nèi)容有重疊,src的內(nèi)容也可以正確地被拷貝到了dest指向的空間。

內(nèi)存重疊的拷貝

這種情況下,src的地址小于dest的地址,拷貝前3個(gè)字節(jié)沒問題,但是拷貝第4,5個(gè)字節(jié)時(shí),原有的內(nèi)容已經(jīng)被src拷貝過來的字符覆蓋了,所以已經(jīng)丟失原來src的內(nèi)容,這很明顯就是問題所在。

memcpy的實(shí)現(xiàn)##

一般來說,memcpy的實(shí)現(xiàn)非常簡(jiǎn)單,只需要順序的循環(huán),把字節(jié)一個(gè)一個(gè)從src拷貝到dest就行:

#include <stddef.h> /* size_t */
void *memcpy(void *dest, const void *src, size_t n)
{
    char *dp = dest;
    const char *sp = src;
    while (n--)
        *dp++ = *sp++;
    return dest;
}

memmove的實(shí)現(xiàn)##

memmove會(huì)對(duì)拷貝的數(shù)據(jù)作檢查,確保內(nèi)存沒有覆蓋,如果發(fā)現(xiàn)會(huì)覆蓋數(shù)據(jù),簡(jiǎn)單的實(shí)現(xiàn)是調(diào)轉(zhuǎn)開始拷貝的位置,從尾部開始拷貝:

#include <stddef.h> /* for size_t */
void *memmove(void *dest, const void *src, size_t n)
{
    unsigned char *pd = dest;
    const unsigned char *ps = src;
    if (__np_anyptrlt(ps, pd))
        for (pd += n, ps += n; n--;)
            *--pd = *--ps;
    else
        while(n--)
            *pd++ = *ps++;
    return dest;
}

這里__np_anyptrlt是一個(gè)簡(jiǎn)單的宏,用于結(jié)合拷貝的長(zhǎng)度檢測(cè)dest與src的位置,如果dest和src指向同樣的對(duì)象,且src比dest地址小,就需要從尾部開始拷貝。否則就和memcpy處理相同。
但是實(shí)際在C99實(shí)現(xiàn)中,是將內(nèi)容拷貝到臨時(shí)空間,再拷貝到目標(biāo)地址中:

#include <stddef.h> /* for size_t */
#include <stdlib.h> /* for memcpy */

void *memmove(void *dest, const void *src, size_t n)
{
    unsigned char tmp[n];
    memcpy(tmp,src,n);
    memcpy(dest,tmp,n);
    return dest;
}

由此可見memcpy的速度比memmove快一點(diǎn),如果使用者可以確定內(nèi)存不會(huì)重疊,則可以選用memcpy,否則memmove更安全一些。另外一個(gè)提示是第三個(gè)參數(shù)是拷貝的長(zhǎng)度,如果你是拷貝10個(gè)double類型的數(shù)值,要寫成sizeof(double)*10,而不僅僅是10。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,370評(píng)論 0 6
  • 1.寫一個(gè)NSString類的實(shí)現(xiàn) +(id)initWithCString:(c*****t char *)nu...
    韓七夏閱讀 3,805評(píng)論 2 37
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 2,014評(píng)論 0 7
  • 多線程、特別是NSOperation 和 GCD 的內(nèi)部原理。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景。SDWebImage的原...
    LZM輪回閱讀 2,043評(píng)論 0 12
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛DE問候閱讀 1,762評(píng)論 0 4