第一種:最常見的:
void* memcpy( void* dest, const void* src, size_t count )
{
if (count<0)
{printf("Invalid count number !.\n");
return (void*)0;}
if(src==NULL||dest==NULL)
return (void*)0 ;
if ((unsigned int)dest==(unsigned int)src)
{printf("The source is equal with the destanation!.\n");
return dest;}
char* d = (char*)dest;
const char* s = (const char*)src;
while(count--)
*d++ = *s++;
return dest;
}
另一個實現,和上面類似,轉貼高質量C++/C編程指南中的,供參考:
void *memcpy(void *pvTo, const void *pvFrom, size_t size)
{
assert((pvTo != NULL) && (pvFrom != NULL)); // 使用斷言
byte *pbTo = (byte *) pvTo; // 防止改變pvTo的地址
byte *pbFrom = (byte *) pvFrom; // 防止改變pvFrom的地址
while(size -- > 0 )
*pbTo ++ = *pbFrom ++ ;
return pvTo;
}
第二種:轉自變態之MEMCPY
void* mymemcpy( void* dest, const void* src, size_t count )
{
char* d = (char*)dest;
const char* s = (const char*)src;
int n = (count + 7) / 8; // count > 0 assumed
switch( count & 7 )
{
case 0: do { *d++ = *s++;
case 7: *d++ = *s++;
case 6: *d++ = *s++;
case 5: *d++ = *s++;
case 4: *d++ = *s++;
case 3: *d++ = *s++;
case 2: *d++ = *s++;
case 1: *d++ = *s++;
} while (--n > 0);
}
return dest;
}
解釋:摘自原貼:
int n = (count + 7) / 8;計算要復制的輪數(每輪復制8位),剩下的余數位數也要復制進去。
count & 7控制要復制余數位數,while (--n > 0)控制輪數。
比如count = 9,則n = 2,count & 7 = 1,要復制2輪,程序跳到case1執行,復制一位之後,再循環一輪,復制8位.
為何這麼實現:引用上面帖子後面的評論:
每8個字節拷貝省7個跳轉(AMD處理器內部分支預測算法是“假定全都跳轉”,因此這裡也就是相當於省了7個時鐘周期);把swith和do循環湊到一起,多少省幾個字節的空間……
但使用32位或64位指令,可以得到更大的優化效果,代碼還要精煉得多。
說實在話:除非內存小到極點、並且無法增加的系統,寫出這樣的程序純屬作孽……
後記:一般出題目讓你實現memcpy,個人理解,其意圖至少有以下幾點:
1.寫任何程序都能反映出你的代碼風格.
2.考查你是否注意到,要拷貝的源,即const void* src,應該是用const的,避免有意或無意的修改.
3.考查你,不應該直接對src和dst指針進行類似++或--之類的操作,而應該另外申請對應變量用於此操作.
4.指針的類型轉化問題,原始參數應該是void *的,你具體操作的時候,應該是轉化為某種具體的類型,此處用char比較適合.
5.注意要判斷源src是否和dest重復,如果重復,直接返回或返回錯誤.
6.應該還有其他考慮,如果以後想到,再補充.
補充:後來又重新看了高質量C++/C編程指南,其中,原作者直接對const char *strSrc和strDest進行++操作
char *strcpy(char *strDest, const char *strSrc);
{
assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
char *address = strDest; // 2分
while( (*strDest++ = * strSrc++) != ‘\0’ ) // 2分
NULL ;
return address ; // 2分
}
此時我才注意到,自己總結的上面第三點,是錯誤的,因為const char *strSrc中的const是指字符串內容為const,而不是說strSrc是const的,如果要指定strSrc是const,應該寫成 char * const strSrc 。
不過,對此,有人也許又該問了,那此處對strSrc進行++操作,不是破壞了原先strSrc的指向了嗎?
如果你真是這麼問,那麼說明你的概念還不是很清楚(我開始也是和你犯了同樣錯誤),實際上這點在高質量C++/C編程指南,也有提及,因為strSrc是函數的形參,而此處雖然對形參的進行++ 操作,改變其指向,但是並沒有改變原始屬性為const的字符串,而且此處的形參,在函數調用結束之後,也就釋放了,對原始傳來的地址,沒有任何影響。