memcpy函數(shù)實(shí)現(xiàn)及其優(yōu)化
1:函數(shù)原型void * memcpy ( void * destination, const void * source, size_t num );
函數(shù)作用
參考: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)。
實(shí)現(xiàn)1:《高質(zhì)量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類(lèi)型
byte * pdst = (byte *)dst;
while(num--》0)*pdst++ = *psrc++;
return dst;
}
缺點(diǎn):沒(méi)有考慮內(nèi)存重疊的情況,可以加一個(gè)斷言換為:assert(des》=src+num||src》dst+num);
實(shí)現(xiàn)2:考慮重疊,有重疊情況也復(fù)制
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;
}
對(duì)memcpy函數(shù)的改進(jìn):
改進(jìn)思想:
大部分認(rèn)為memcpy是一個(gè)char到char的拷貝的循環(huán),擔(dān)心它的效率。實(shí)際上,memcpy是一個(gè)效率最高的內(nèi)存拷貝函數(shù),他不會(huì)那么傻,來(lái)做一個(gè)一個(gè)字節(jié)的內(nèi)存拷貝,在地址不對(duì)齊的情況下,他是一個(gè)字節(jié)一個(gè)字節(jié)的拷,地址對(duì)齊以后,就會(huì)使用CPU字長(zhǎng)來(lái)拷(和dma類(lèi)似),32bit或64bit,還會(huì)根據(jù)cpu的類(lèi)型來(lái)選擇一些優(yōu)化的指令來(lái)進(jìn)行拷貝??偟膩?lái)說(shuō),memcpy的實(shí)現(xiàn)是和CPU類(lèi)型、操作系統(tǒng)、cLib相關(guān)的。毫無(wú)疑問(wèn),它是內(nèi)存拷貝里效率最高的,請(qǐng)放心使用。
1 void *mymemcpy(void *dst,const void *src,size_t num)
2 {
3 assert((dst!=NULL)&&(src!=NULL));
4 int wordnum = num/4;//計(jì)算有多少個(gè)32位,按4字節(jié)拷貝
5 int slice = num%4;//剩余的按字節(jié)拷貝
6 int * pintsrc = (int *)src;
7 int * pintdst = (int *)dst;
8 while(wordnum--)*pintdst++ = *pintsrc++;
9 while (slice--)*((char *)pintdst++) =*((char *)pintsrc++);
10 return dst;
11 }
memcpy函數(shù)用法詳解
1、memcpy 函數(shù)用于 把資源內(nèi)存(src所指向的內(nèi)存區(qū)域) 拷貝到目標(biāo)內(nèi)存(dest所指向的內(nèi)存區(qū)域);拷貝多少個(gè)?有一個(gè)size變量控制
拷貝的字節(jié)數(shù);
函數(shù)原型:void *memcpy(void *dest, void *src, unsigned int count);
用法:(1)可以拷貝任何類(lèi)型的對(duì)象,因?yàn)楹瘮?shù)的參數(shù)類(lèi)型是void*(未定義類(lèi)型指針),也就是說(shuō)傳進(jìn)去的實(shí)參可以是int*,short*,char*等等,
但是由于函數(shù)拷貝的過(guò)程是一個(gè)字節(jié)一個(gè)字節(jié)的拷貝的,所以實(shí)際操作的時(shí)候要把void*強(qiáng)制轉(zhuǎn)化為char*,這樣在指針加的時(shí)候才會(huì)保證每次加一個(gè)字節(jié),呵呵
函數(shù)源代碼實(shí)現(xiàn):
void *memcpy1(void *desc,const void * src,size_t size)
{
if((desc == NULL) && (src == NULL))
{
return NULL;
}
unsigned char *desc1 = (unsigned char*)desc;
unsigned char *src1 = (unsigned char*)src;
while(size-- 》0)
{
*desc1 = *src1;
desc1++;
src1++;
}
return desc;
}
int _tmain(int argc, _TCHAR* argv[])
{
int dest[2] = {0};
const char src[5] = “1234”;
//printf(src);
memcpy1(dest,src,sizeof(src));
//*(dest+5) = ‘/0’;
printf((char *)dest);
int m = -1;
return 0;
}
123456789101112131415161718192021222324252627
注意事項(xiàng):(1)void* 一定要返回一個(gè)值(指針),這個(gè)和void不太一樣!
?。?)首先要判斷指針的值不能為空,desc為空的話肯定不能拷貝內(nèi)存空間,src為空相當(dāng)于沒(méi)有拷貝;所以之間return掉;
?。?)”“空串是指內(nèi)容為0,NULL是0,不是串;兩個(gè)不等價(jià);
?。?)int dest[2] = {0};這是對(duì)int 類(lèi)型的數(shù)組初始化的方法;如果是char類(lèi)型,就用char a[5] = “1234”; 注意數(shù)組下標(biāo)要
多于實(shí)際看到的字符數(shù),因?yàn)檫€有’/0’
?。?)printf((char *)dest);這句話,是把 char 類(lèi)型 src 傳到 int 類(lèi)型的 dest的內(nèi)存強(qiáng)制轉(zhuǎn)化成char類(lèi)型,然后打印出來(lái);
因?yàn)橹苯涌磇nt類(lèi)型的dest是看不到里面的內(nèi)容的;因?yàn)橛衭nsigned char desc1 = (unsigned char)desc;所以字符可以傳
到dest里面保存起來(lái),dest所指向的內(nèi)存長(zhǎng)度4個(gè)字節(jié),強(qiáng)制轉(zhuǎn)化為char 就是把四個(gè)字節(jié)分成一個(gè)一個(gè)的字節(jié),這樣就可以看到
一個(gè)個(gè)字符了,如果定義成char dest[5] = “1234”;就不用轉(zhuǎn)化;呵呵,表達(dá)起來(lái)真累人;
?。?)memcpy1(dest,src,sizeof(src));注意里面的sizeof(src),這個(gè)是包括字符串的結(jié)束符’/0’的;所以不用擔(dān)心printf(dest);
但是如果用memcpy1(dest,src,4);沒(méi)有’/0’就要*(dest+5) = ‘/0’;這樣保證是一個(gè)完整的字符串;
?。?)如果初始化的時(shí)候:
char dest[1024] = “12345666”;//{0};
const char src[5] = “3333”;
那么拷貝的時(shí)候,如果用memcpy1(dest,src,sizeof(src));則printf(dest);出來(lái)是3333
如果memcpy1(dest,src,4);則printf(dest);出來(lái)是33335666;因?yàn)樯厦娴膕izeof(src),包含’/0’,所以拷貝過(guò)去的字符串以’/0’
結(jié)束,就只有3333,而如果傳4個(gè)字符,’/0’是第五個(gè)字符,那就遇到dest[1024] 的’/0’結(jié)束,所以是33335666
字符串的’/0’問(wèn)題一定要注意?。。?!
實(shí)際應(yīng)用:
unsigned char g_pData[1024] = “”;
DWORD g_dwOffset = 0;
bool PackDatatoServer(const unsigned char *pData, const unsigned int uSize)
{
memcpy(g_pData+g_dwOffset, pData, uSize);
g_dwOffset += uSize;
//g_pData += uSize;
return true;
}
void main()
{
const unsigned char a[4] = “123”;
PackDatatoServer(a, 3);
PackDatatoServer(a, 1111);
int b = -1;
}
12345678910111213141516
PackDatatoServer()函數(shù)的作用是把每次的資源內(nèi)存拷貝到目標(biāo)內(nèi)存里面,而且是累加的拷貝;也就是后一次緊接著上一次的拷貝;
顯然用到了memcpy函數(shù);
實(shí)現(xiàn)原理是用到了一個(gè)全局變量g_dwOffset 保存之前拷貝的長(zhǎng)度,最開(kāi)始沒(méi)有想到這一點(diǎn),結(jié)果每次拷貝都是一次性的,下一次拷貝把
上一次的沖掉了;所以用全局變量記錄拷貝的長(zhǎng)度;
第二個(gè)需要注意的是,拷貝的過(guò)程中注意不要改變目標(biāo)指針的指向,即目標(biāo)指針始終指向初始化的時(shí)候指向的位置;那么怎么實(shí)現(xiàn)累積拷貝呢?
就是用的指針偏移;第一次實(shí)現(xiàn)的時(shí)候,把g_pData += uSize;寫(xiě)到了函數(shù)里面,這樣寫(xiě)是能夠?qū)崿F(xiàn)指針位移的目標(biāo),但是指針指向也發(fā)生改變;
另外:g_pData += uSize;也有報(bào)錯(cuò):left operand must be l-value,原因是:把地址賦值給一個(gè)不可更改的指針!
比如:
char a[100];
char *p = new char[10];
a = p; //這里出錯(cuò),注意了:數(shù)組的首地址也是一個(gè)常量指針,指向固定不能亂改的~~
char * const pp = new char[1];
pp = a; //也錯(cuò)
123456
所以既不能改變首地址,又要滿足累積賦值(就是賦值的時(shí)候要從賦過(guò)值的地方開(kāi)始向下一個(gè)內(nèi)存塊賦值,想到指針加),所以想到把指針加寫(xiě)到
函數(shù)參數(shù)里面,這時(shí)就要充分了解memcpy的實(shí)現(xiàn)過(guò)程,里面是一個(gè)一個(gè)字符的賦值的,想連續(xù)賦值,就要把指針指向連續(xù)的內(nèi)存的首地址,所以,真的很不好表達(dá)就這樣了。
責(zé)任編輯:YYX
評(píng)論