C++的Memcpy與Memcpy_s函數解析

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超過這個緩衝區的時候就開始溢出
   可能影響內存中下一個地址
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章