Memcpy函數
一. 函數內容
** 1.1函數原型 **
void * Memcpy(void * dest,const void * src,size_t count)這是一個函數指針 接收的是一個地址 dest是接收地址的首地址,src是源首地址,count是接收目標的大小單位爲字節 位於cstring或memcpy.h頭文件中。
windows中Memcpy的函數原型
void* __cdecl memcpy(void* dst,const void* src,size_t count)
{
void*ret=dst;
{
extern void RtlMoveMemory(void *,const void *,size_t count);
RtlMoveMemory(dst,src,count);
}
while(count--){
*(char *)dst = *(char *)src;
dst = (char *)dst+1;
src = (char *)src+1;
}
return (ret);
}
使用注意事項:
1.-src地址是否爲空,
2.-src和dest地址是否重合,是安全重合還是部分重合
3.當處與大塊數據時候可能存在,效率低下問題。
改進之後的memcpy
void *my_memcpy_byte(void *dst, const void *src, int n)
{
if (dst == NULL || src == NULL || n <= 0)
return NULL;
char * pdst = (char *)dst;
char * psrc = (char *)src;
if (pdst > psrc && pdst < psrc + n)
{
pdst = pdst + n - 1;
psrc = psrc + n - 1;
while (n--)
*pdst-- = *psrc--;
}
else
{
while (n--)
*pdst++ = *psrc++;
}
return dst;
}
linux版本
void *memcpy(void *to, const void *from, size_t n)
{
void *xto = to;
size_t temp, temp1;
if (!n)
return xto;
if ((long)to & 1) {
char *cto = to;
const char *cfrom = from;
*cto++ = *cfrom++;
to = cto;
from = cfrom;
n--;
}
if (n > 2 && (long)to & 2) {
short *sto = to;
const short *sfrom = from;
*sto++ = *sfrom++;
to = sto;
from = sfrom;
n -= 2;
}
temp = n >> 2;
if (temp) {
long *lto = to;
const long *lfrom = from;
#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
for (; temp; temp--)
*lto++ = *lfrom++;
#else
asm volatile (
" movel %2,%3\n"
" andw #7,%3\n"
" lsrl #3,%2\n"
" negw %3\n"
" jmp %%pc@(1f,%3:w:2)\n"
"4: movel %0@+,%1@+\n"
" movel %0@+,%1@+\n"
" movel %0@+,%1@+\n"
" movel %0@+,%1@+\n"
" movel %0@+,%1@+\n"
" movel %0@+,%1@+\n"
" movel %0@+,%1@+\n"
" movel %0@+,%1@+\n"
"1: dbra %2,4b\n"
" clrw %2\n"
" subql #1,%2\n"
" jpl 4b"
: "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
: "0" (lfrom), "1" (lto), "2" (temp));
#endif
to = lto;
from = lfrom;
}
if (n & 2) {
short *sto = to;
const short *sfrom = from;
*sto++ = *sfrom++;
to = sto;
from = sfrom;
}
if (n & 1) {
char *cto = to;
const char *cfrom = from;
*cto = *cfrom;
}
return xto;
}
二.函數使用
#include<stdio.h>
#include<string.h>
int main(void)
{
char src[]="******************************";
char dest[]="abcdefghijlkmnopqrstuvwxyz0123as6";
printf("destination before memcpy:%s\n",dest);
memcpy(dest,src,strlen(src));
printf("destination after memcpy:%s\n",dest);
return 0;
}
##輸出爲
destination before memcpy:abcdefghijlkmnopqrstuvwxyz0123as6
destination after memcpy: ******************************as6
Memcpy_s函數
void *dest,
size_t numberOfElements,
const void *src,
size_t count
);
以下是查看其他資料收集出來的
~~ 第一個參數爲目標內存地址,第二個參數爲目標內存緩衝大小,第三個參數爲源內存地址,第四個爲源內存緩衝的大小。返回值是一個錯誤碼。
爲什麼這個返回值是錯誤碼呢?因爲這個版本中加入了基本的錯誤檢測。如果源緩衝大小爲0,即count爲0,函數返回0,什麼也不做。此函數沒有對目標指針爲NULL的情況,不做檢查,所以你自己要注意檢查。如果指針有值,但是是無效值,函數也沒辦法檢查是否是有效內存,只是會蒐集這些信息,在程序崩潰時提供調試需要的信息。
然後檢查源地址是否爲空或count是否大於sizeInBytes,兩個條件有一個滿足,函數中先將目標內存以sizeInBytes指定的大小調用memset函數清0.這裏可以看出,如果sizeInBytes傳入的大小超出目標緩衝區的大小,也是會帶來隱患的,一旦清除了其他進程的或者其他線程的內存,都是帶來問題,也很可能導致內存操作違規。所以,第二個參數的大小不能超過目標緩衝的大小,以字節爲單位。然後程序蒐集錯誤信息,最後返回錯誤碼,並不會執行內存複製的過程。前面說的這是兩個條件任意一個進入都會導致失敗,所以在蒐集信息時,程序會對進入的條件進行判斷,然後進行蒐集。
只有這些檢查通過,纔會調用memcpy函數執行內存複製過程。而第二個參數只是內部用來檢測和清除目標內存而使用的。
函數memcpy_s執行完畢後返回0,所以檢查返回值是否爲0不能判斷是否成功。但是返回值爲非零那就是失敗了。
雖然說加上_s版本的函數是安全版本,但是也是會出現問題的,使用時也要注意,即使有時候不崩潰,但是一旦改寫了其他的線程的內存,必然導致程序運行不正常,因爲線程的數據被破壞,至少邏輯會出錯。
不過,_s版本函數提供了一定的檢測,並且在release版本也可以報錯,可以進一步調試問題,而memcpy則在release版本中不會報錯 ~~
--
函數 memcpy_s( void *dest, size_t numberOfElements, const void *src, size_t count ),
先申請了一個緩衝區大小,爲numberofelements,當count超過這個緩衝區的時候就開始溢出
可能影響內存中下一個地址