天天看點

memcpy 函數實作

memcpy函數的作用:

将由src指向位址為起始位址的連續n個位元組的資料複制到以dest指向位址為起始位址的空間内,函數傳回一個指向dest的指針。

想必大多數人在面試時被要求寫 memcpy的實作,很不幸,我也吃過這個虧(這種題要是寫的一塌糊塗後面完全沒戲),是以還是得提前準備一下,不然就隻能呵呵了。

先來看看一段錯誤的示範: 找茬

void * memcpy(void *dest, const void *src, unsigned int count);

{

if ((src == NULL) || (dest == NULL))

return;

while (count--) *dest++ = *src++;

return dest;

}

特别說明:

1、與strcpy相比,memcpy遇到'\0'不會結束,而是一定要拷貝完n個位元組,是以要指定拷貝的資料長度

2、memcpy可以拷貝任何資料類型的對象,如果dest和src的指針類型不一樣,也需要處理,不能直接++使位址自增(例如: int* p和 char*q, p++指針的值是4個4個加(0,4,8),q++是1個1個加(0,1,2,3,4))

3、如果dest本身就有資料,執行memcpy()之後會覆寫原有的資料,是以src和dest所指向的記憶體區域不能有重疊

4、不能改變形參的值,定義新的臨時變量來操作

5、參數提供的位址可能為空

完善後的代碼:

void *memcpy(void *dest, const void *src, size_t count)

{

if (dest == NULL || src == NULL )

{

return NULL;

}

char *tmp_dest = dest;

const char *tmp_src = src;

while (count--) *tmp_dest++ = *tmp_src++ ;

return dest;

}

這樣寫的代碼文法上看起來沒什麼問題了,但是不要忘記 src和dest所指向的記憶體區域不能有重疊,是以上面這段代碼還是有bug。這個算是不容易看出來的bug,如果這樣寫了以後代碼出現問題就很難排除了,這也就是為什麼寫不好這個函數指定會被淘汰的原因了。

dest和src所指向的位址有重疊的情況

記憶體位址重疊的情況分為兩種,第一種是dest的位址在src位址的後面,另一種則是dest位址在src位址的前面。

這兩種情況在memcpy中都是不允許出現的,需要在代碼中處理以避免。

為了處理上面這兩種情況,後來又提供了另一個函數memmove,在不需要保留原來記憶體區域的資料的時候可以使用memmove。

最終的正确的版本:

void *memcpy(void *dest, const void *src, size_t count)

{

if (dest == NULL || src == NULL || dest <= src+count)

{

return NULL;

}

char *tmp_dest = dest;

const char *tmp_src = src;

while (count--) *tmp_dest++ = *tmp_src++ ;

return dest;

}

上面就是正确的版本了,我所能考慮到的問題都處理了。

另外,這段代碼還可以優化,比如根據CPU的位元組長度,把原來一個一個位元組拷貝轉換為按CPU的長度拷貝,等等。

感興趣的話自己研究一下吧,這裡就不介紹了。