memcpy和memmove都是C語(yǔ)言的庫(kù)函數(shù)形帮,相比于strcpy和strncpy只能拷貝字符串?dāng)?shù)組肤无,memcpy與memmove可以拷貝其它類(lèi)型的數(shù)組先蒋,但是為什么要同時(shí)提供兩種方法呢?本文主要就是介紹這兩個(gè)函數(shù)的區(qū)別宛渐。
首先來(lái)看函數(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ū)域沒(méi)有數(shù)據(jù)重疊,而memmove沒(méi)有這個(gè)前提條件窥翩。如果復(fù)制的兩個(gè)區(qū)域存在重疊時(shí)使用memcpy业岁,其結(jié)果是不可預(yù)知的,有可能成功也有可能失敗的寇蚊,所以如果使用了memcpy,程序員自身必須確保兩塊內(nèi)存沒(méi)有重疊部分笔时。
我們來(lái)看一組示例:
正常情況下,即使內(nèi)容有重疊仗岸,src的內(nèi)容也可以正確地被拷貝到了dest指向的空間允耿。
這種情況下借笙,src的地址小于dest的地址,拷貝前3個(gè)字節(jié)沒(méi)問(wèn)題较锡,但是拷貝第4业稼,5個(gè)字節(jié)時(shí),原有的內(nèi)容已經(jīng)被src拷貝過(guò)來(lái)的字符覆蓋了蚂蕴,所以已經(jīng)丟失原來(lái)src的內(nèi)容低散,這很明顯就是問(wèn)題所在。
memcpy的實(shí)現(xiàn)##
一般來(lái)說(shuō)掂墓,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)存沒(méi)有覆蓋跨嘉,如果發(fā)現(xiàn)會(huì)覆蓋數(shù)據(jù),簡(jiǎn)單的實(shí)現(xiàn)是調(diào)轉(zhuǎn)開(kāi)始拷貝的位置吃嘿,從尾部開(kāi)始拷貝:
#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地址小亮瓷,就需要從尾部開(kāi)始拷貝。否則就和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;
}
由此可見(jiàn)memcpy的速度比memmove快一點(diǎn)挣饥,如果使用者可以確定內(nèi)存不會(huì)重疊除师,則可以選用memcpy,否則memmove更安全一些扔枫。另外一個(gè)提示是第三個(gè)參數(shù)是拷貝的長(zhǎng)度汛聚,如果你是拷貝10個(gè)double類(lèi)型的數(shù)值,要寫(xiě)成sizeof(double)*10,而不僅僅是10短荐。