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也有優化
5.是否需要考慮內存對齊拷貝?
內存讀寫效率影響之一:內存對齊
參考:1.淺談CPU內存訪問要求對齊的原因 2.解析內存對齊
如果src,dst的地址是不對齊的,讀寫效率變低。
通過代碼實現不對齊的拷貝,memcpy的實現會變得復雜,反而影響拷貝效率。
這種不對齊情況我們可以預先避免,因為編譯器在給我們分配空間時是按照內存對齊進行分配的。
6.根據拷貝數據大小進行優化
1.多次調用memcpy,而每次拷貝數據大小Kb下的小拷貝
這種情況下盡量減少分支預測,代碼精簡。
2.拷貝Mb的memcpy實現
這種情況影響拷貝效率主要在尋址上。
7.總結
memcpy需要根據情況優化,如 平台,處理器,拷貝大小。