天天看點

memcpy函數實作及其優化

1:函數原型void * memcpy ( void * destination, const void * source, size_t num );

函數作用

參考:http://www.cplusplus.com/reference/clibrary/cstring/memcpy/

Copy block of memory Copies the values of  num bytes from the location pointed by  source directly to the memory block pointed by  destination.

The underlying type of the objects pointed by both the  source and  destination pointers are irrelevant for this function; The result is a binary copy of the data.

The function does not check for any terminating null character in  source - it always copies exactly  num bytes.

To avoid overflows, the size of the arrays pointed by both the  destination and  source parameters, shall be at least  numbytes, and should not overlap (for overlapping memory blocks,  memmove is a safer approach).

實作1:《高品質c++,c程式設計指南》

void *mymemcpy(void *dst,const void *src,size_t num)
{
	assert((dst!=NULL)&&(src!=NULL));
          //assert(des>=src+num||src>dst+num);
	byte * psrc = (byte *)src;//byte 既為unsigned char類型
	byte * pdst = (byte *)dst;
	while(num-->0)*pdst++ = *psrc++;
	return dst;
}
           

缺點:沒有考慮記憶體重疊的情況,可以加一個斷言換為:assert(des>=src+num||src>dst+num);

實作2:考慮重疊,有重疊情況也複制

void * mymemcpy(void *dest, const void *src, size_t count)
{
    if (dest == NULL || src == NULL)
          return NULL;
    char *pdest = static_cast <char*>(dest);
    const char *psrc  = static_cast <const char*>(psrc);
    int n = count;
    
    if (pdest > psrc && pdest < psrc+count)
    {
        for (size_t i=n-1; i != -1; --i)
        {
                pdest[i] = psrc[i];
        }
    }
    else
    {
        for (size_t i= 0; i < n; i++)
        {
                pdest[i] = psrc[i];
        }
    }
    
    return dest;
}
           

對memcpy函數的改進:

改進思想:

大部分認為memcpy是一個char到char的拷貝的循環,擔心它的效率。實際上,memcpy是一個效率最高的記憶體拷貝函數,他不會那麼傻,來做一個一個位元組的記憶體拷貝,在位址不對齊的情況下,他是一個位元組一個位元組的拷,位址對齊以後,就會使用CPU字長來拷(和dma類似),32bit或64bit,還會根據cpu的類型來選擇一些優化的指令來進行拷貝。總的來說,memcpy的實作是和CPU類型、作業系統、cLib相關的。毫無疑問,它是記憶體拷貝裡效率最高的,請放心使用。

void *mymemcpy(void *dst,const void *src,size_t num)
{
	assert((dst!=NULL)&&(src!=NULL));
	int wordnum = num/4;//計算有多少個32位,按4位元組拷貝
	int slice = num%4;//剩餘的按位元組拷貝
	int * pintsrc = (int *)src;
	int * pintdst = (int *)dst;
	while(wordnum--)*pintdst++ = *pintsrc++;
	while (slice--)*((char *)pintdst++) =*((char *)pintsrc++);
	return dst;
}
           

參考:

繼續閱讀