實現memcpy()函數及過程總結


1.為什么會寫memcpy

在之前的應聘筆試上遇到一道筆試題,題目要求實現一個my_memcpy函數。函數原型:void * my_memcpy(void *dst, const void *src, int n);

之前使用的內存拷貝函數是標准庫memcpy函數,拿來就用,真沒有對這個函數做過多了解。在網上查了一下,有好多關於memcpy函數優化的文章。

在實現過程中了解的越多,往往實現起來越麻煩。還是先實現簡單的memcpy函數。

2.按字節(Byte)拷貝實現的memcpy

 1 void *my_memcpy_byte(void *dst, const void *src, int n)
 2 {
 3     if (dst == NULL || src == NULL || n <= 0)
 4         return NULL;
 5 
 6     char * pdst = (char *)dst;
 7     char * psrc = (char *)src;
 8 
 9     if (pdst > psrc && pdst < psrc + n)
10     {
11         pdst = pdst + n - 1;
12         psrc = psrc + n - 1;
13         while (n--)
14             *pdst-- = *psrc--;
15     }
16     else
17     {
18         while (n--)
19             *pdst++ = *psrc++;
20     }
21     return dst;
22 }
    //20200104 看到評論,又看了下之前寫的memcpy實現
    //按字節拷貝實現的memcpy沒有問題
    //*pdst-- = *psrc--; 查了下運算符優先級(*,--)優先級相同,從右向左結合,psrc--是先使用,后減減
    //等價於*pdst = *psrc;psrc--;pdst--;

 這里要考慮寫覆蓋的情況

3.按4字節拷貝實現的memcpy

 1 void *my_memcpy(void *dst, const void *src, int n)
 2 {
 3     if (dst == NULL || src == NULL || n <= 0)
 4         return NULL;
 5 
 6     int * pdst = (int *)dst;
 7     int * psrc = (int *)src;
 8     char *tmp1 = NULL;
 9     char *tmp2 = NULL;
10     int c1 = n / 4;
11     int c2 = n % 4;
12 
13     /*if (pdst > psrc && pdst < psrc + n) 這樣判斷有問題*/
14     if (pdst > psrc && pdst < (char *)psrc + n)
15     {
16         tmp1 = (char *)pdst + n - 1;
17         tmp2 = (char *)psrc + n - 1;
18         while(c2--)
19             *tmp1-- = *tmp2--;
20         /*這樣有問題,忘記字節偏移
21         pdst = (int *)tmp1;
22         psrc = (int *)tmp2;
23         */
24         tmp1++;tmp2++;
25         pdst = (int *)tmp1;
26         psrc = (int *)tmp2;
27         pdst--;psrc--;
28         while (c1--)
29             *pdst-- = *psrc--;
30     }
31     else
32     {
33         while (c1--)
34             *pdst++ = *psrc++;
35
36
tmp1 = (char *)pdst; 37 tmp2 = (char *)psrc; 38 while (c2--) 39 *tmp1++ = *tmp2++; 40 } 41 return dst; 42 }
      //20200104 查看評論說四字節寫覆蓋拷貝問題,現在已修改
      //備注:void *dst, const void *src這兩個參數是需要按4字節對齊的,如果本身不是4字節對齊,按4字節拷貝效率也會變低。

這里還是考慮了寫覆蓋的代碼。對比按字節拷貝,拷貝速度是提高不少。

以上是針對筆試過程中寫memcpy。

4.如何優化memcpy

高性能的memcpy與很多因數相關,與平台,處理器,編譯器,具體拷貝情形等相關。

VS2017中對C庫的memcpy進行優化,glibc對memcpy也有優化

參考:怎樣寫出一個更快的 memset/memcpy ?

5.是否需要考慮內存對齊拷貝?

內存讀寫效率影響之一:內存對齊

參考:1.淺談CPU內存訪問要求對齊的原因     2.解析內存對齊

如果src,dst的地址是不對齊的,讀寫效率變低。

通過代碼實現不對齊的拷貝,memcpy的實現會變得復雜,反而影響拷貝效率。

這種不對齊情況我們可以預先避免,因為編譯器在給我們分配空間時是按照內存對齊進行分配的

6.根據拷貝數據大小進行優化

1.多次調用memcpy,而每次拷貝數據大小Kb下的小拷貝

  這種情況下盡量減少分支預測,代碼精簡。

2.拷貝Mb的memcpy實現

  這種情況影響拷貝效率主要在尋址上。

參考:閑着沒事測了一下memcpy

7.總結

memcpy需要根據情況優化,如 平台,處理器,拷貝大小。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM