一:strcpy函數用法和實現:
[cpp]
/*
GNU-C中的實現(節選):
*/
char* strcpy(char *d, const char *s)
{
char *r=d;
while((*d++=*s++));
return r;
}
/*
GNU-C中的實現(節選):
*/
char* strcpy(char *d, const char *s)
{
char *r=d;
while((*d++=*s++));
return r;
}
有沒有發現這個實現並不是很好。。至少沒有判斷是不是為NULL。一個更好的版本:
[cpp]
char *strcpy(char *strDest, const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL));
char *address = strDest;
while( (*strDest++ = * strSrc++) != '\0')
return address ;
}
char *strcpy(char *strDest, const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL));
char *address = strDest;
while( (*strDest++ = * strSrc++) != '\0')
return address ;
}
好好研究這段代碼其實寫的挺妙的。。(當然不是我寫的)。。
二:memcpy函數用法和實現:
從源src所指的內存地址的起始位置開始拷貝n個字節到目標dest所指的內存地址的起始位置中
微軟實現:
[cpp]
void * __cdecl memcpy (void * dst,const void * src, size_t count )
{
void * ret = dst;
#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
{
extern void RtlMoveMemory( void *, const void *, size_t count );
RtlMoveMemory( dst, src, count );
}
#else /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
/* * copy from lower addresses to higher addresses */
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
#endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
return(ret);
}
void * __cdecl memcpy (void * dst,const void * src, size_t count )
{
void * ret = dst;
#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
{
extern void RtlMoveMemory( void *, const void *, size_t count );
RtlMoveMemory( dst, src, count );
}
#else /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
/* * copy from lower addresses to higher addresses */
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
#endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
return(ret);
}
寫的是不是也很好。。仿佛天衣無縫啊!。。但是你有沒有注意到一個問題:那就是內存重疊。。
什麼叫內存重疊呢?就是兩塊內存區域有一個共同的部分。。是不是很SB的解釋。。當存在這個問題的時候,那還和我們預期的那樣拷貝嗎?注意:理解了這個才是關鍵。。
例子:(引用網上一個例子)
[cpp]
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a+4, a, sizeof(int)*6)
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a+4, a, sizeof(int)*6) 如果照微軟實現的話,那麼輸出應該是0123012301(理解這個再忘下看吧。。)
而我們想要達到的目的是輸出:0123012345。。如果你實驗一下,確實也是輸出0123012345。。(對於這個問題,我也解釋不了)。為了避免這樣的情況發生,我們找到了一個更好的函數:memmove。。
三:memmove函數用法和實現
用法和memcpy函數一樣。。
實現:
[cpp]
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if((dest + count<source) || (source + count) <dest))
{// 如果沒有重疊區域
while(count--)
*tmp_dest++ = *tmp_source++;
}
else
{ //如果有重疊(反向拷貝)
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*--tmp_dest = *--tmp;
}
return dest;
}
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if((dest + count<source) || (source + count) <dest))
{// 如果沒有重疊區域
while(count--)
*tmp_dest++ = *tmp_source++;
}
else
{ //如果有重疊(反向拷貝)
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*--tmp_dest = *--tmp;
}
return dest;
}
一開始看到這段代碼的時候,覺得好神奇啊。後來發現,其實有個很大的漏洞(先不說那些小問題),那就是內存重疊有兩種情況。其實我覺得該作者也想到了,而且給出了解決辦法。,估計是粗心大意吧。
:src<dest&&src+count>dest; dest<src&&dest+count>src。。但是網上那位作者沒有寫清楚,下面我就重寫一下上面的else部分:
[cpp]
else
{
//重疊1:(反向拷貝)
if(tmp_source<=tmp_dest&&tmp_source+count>=tmp_dest)
{
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*tmp_dest-- = *tmp_source--;
}
//重疊2:(正向拷貝)
else
{
while (count--)
{
*tmp_dest++=*tmp_source++;
}
}
}
else
{
//重疊1:(反向拷貝)
if(tmp_source<=tmp_dest&&tmp_source+count>=tmp_dest)
{
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*tmp_dest-- = *tmp_source--;
}
//重疊2:(正向拷貝)
else
{
while (count--)
{
*tmp_dest++=*tmp_source++;
}
}
}
但寫完之後發現傻逼了。。後面的那個else不可以和前面的那個if寫在一起麼?所以優化後的完整代碼:
[cpp]
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if(tmp_source<=tmp_dest&&tmp_source+count>=tmp_dest)
{
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*tmp_dest-- = *tmp_source--;
}
else
{
while (count--)
{
*tmp_dest++=*tmp_source++;
}
}
return tmp_dest;
}
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if(tmp_source<=tmp_dest&&tmp_source+count>=tmp_dest)
{
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*tmp_dest-- = *tmp_source--;
}
else
{
while (count--)
{
*tmp_dest++=*tmp_source++;
}
}
return tmp_dest;
}