1.為什麼會寫memcpy 在之前的應聘筆試上遇到一道筆試題,題目要求實現一個my_memcpy函數。函數原型:void * my_memcpy(void *dst, const void *src, int n); 之前使用的記憶體拷貝函數是標準庫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 }
在上面按位元組拷貝中考慮了拷貝覆蓋,連續的一段空間存放數據是從低地址到高地址進行存放。先從源地址讀出數據,然後寫入到目的地址空間中。目的空間的起始地址如果在源數據空間之內就會出現記憶體覆蓋的情況。
這種情況先從尾部拷貝,避免覆蓋數據,不過這種情況也會破壞src空間數據,在src前使用了const關鍵字,也就是空間只讀,在函數內部不修改src空間數據。
而標準庫的memcpy並沒有將寫覆蓋認為是記憶體拷貝,而是記憶體移動。memcpy的src代表一塊記憶體空間,並用const關鍵字修飾,並不希望記憶體塊被破壞。
對於寫覆蓋(這裡是記憶體塊移動)標準庫推薦使用memmove函數。
3.按4位元組拷貝
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 { 15 tmp1 = (char *)pdst + n - 1; 16 tmp2 = (char *)psrc + n - 1; 17 while(c2--) 18 *tmp1-- = *tmp2--; 19 pdst = (int *)tmp1; 20 psrc = (int *)tmp2; 21 while (c1--) 22 *pdst-- = *psrc--; 23 } 24 else 25 { 26 while (c1--) 27 *pdst++ = *psrc++; 28 tmp1 = (char *)pdst; 29 tmp2 = (char *)psrc; 30 while (c2--) 31 *tmp1++ = *tmp2++; 32 } 33 34 return dst; 35 }
這裡還是考慮了寫覆蓋的代碼。對比按位元組拷貝,拷貝速度是提高不少。
以上是針對筆試過程中寫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需要根據情況優化,如 平臺,處理器,拷貝大小。