【轉】實現memcpy函數

原文出處:http://my.oschina.net/renhc/blog/36345

面試中如問到memcpy的實現,那就要小心了,這裏有陷阱。

先看下標準memcpy()的解釋:

void *memcpy(void *dst, const void *src, size_t n);
//If copying takes place between objects that overlap, the behavior is undefined.

注意下面的註釋,對於地址重疊的情況,該函數的行爲是未定義的。

事實上所說的陷阱也在於此,自己動手實現memcpy()時就需要考慮地址重疊的情況。

另外,標準庫也提供了地址重疊時的內存拷貝函數:memmove(),那麼爲什麼還要考慮重寫memcpy()函數呢?

因爲memmove()函數的實現效率問題,該函數把源字符串拷貝到臨時buf裏,然後再從臨時buf裏寫到目的地址,增加了一次不必要的開銷。

下面給出memcpy()的實現,爲了與標準庫函數區分,我們實現其包裹函數:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void *Memcpy(void *dst, const void *src, size_t size);

int main(int argc, char *argv[])
{
    char buf[100] = "abcdefghijk";
    //memcpy(buf+2, buf, 5);
    Memcpy(buf+2, buf, 5);
    printf("%s\n", buf+2);
}

void *Memcpy(void *dst, const void *src, size_t size)
{
    char *psrc;
    char *pdst;

    if(NULL == dst || NULL == src)
    {
        return NULL;
    }

    if((src < dst) && (char *)src + size > (char *)dst) // 自後向前拷貝
    {
        psrc = (char *)src + size - 1;
        pdst = (char *)dst + size - 1;
        while(size--)
        {
            *pdst-- = *psrc--;
        }
    }
    else
    {
        psrc = (char *)src;
        pdst = (char *)dst;
        while(size--)
        {
            *pdst++ = *psrc++;
        }
    }

    return dst;
}


使用Memcpy()的結果:

1 abcdehijk

使用memcpy()的結果:

1 abadehijk

可以看到標準庫函數的源字符串在拷貝的過程中被污染了。


這裏同時給出微軟中的memcpy代碼:

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);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章