Implementation of memcpy () function and Process summary, memcpy Function
1. Why do I write memcpy?
I encountered a written question in the previous application test, and the question required to implement a my_memcpy function. Function prototype: void * my_memcpy (void * dst, const void * src, int n );
The previously used memory copy function is the memcpy function of the standard library, which is used for use. I really didn't know much about this function. I checked it online and found many articles about memcpy function optimization.
The more you understand in the implementation process, the more difficult it is to implement. Implement simple memcpy functions first.
2. memcpy implemented by Byte copy
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 }
In the above, we have consideredCopy OverwriteIn a row, data is stored from low to high. Read data from the source address and write it to the destination address space. If the starting address of the target space is within the source data space, memory overwrites will occur.
In this case, firstCopy from the end,Avoid Overwriting data,This situation will also damage the src space data,InSrcPreviously UsedConstKeyword, that is, Space read-only, not modified within the FunctionSrcSpatial data.
The memcpy of the standard library does not regard write overwrite as memory copy, but memory movement.MemcpyOfSrcRepresents a piece of memory space, and usesConstKeyword modification, does not want the memory block to be destroyed.
We recommend that you use the standard library for writing overwrite (memory block movement ).MemmoveFunction.
3. 4-byte copy
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 }
I have considered it here.Write Overwrite. Compared with byte copy, the copy speed is much higher.
The above is for writing memcpy during the written test.
4. How to optimize memcpy
High-performanceMemcpyIt is related to many factors, such as platforms, processors, compilers, and specific copy cases.
Memcpy of C library is optimized in VS2017, while memcpy is also optimized in glibc.
Reference: How to Write a faster memset/memcpy?
5. Do I need to consider memory alignment copy?
Memory read/write efficiency: Memory alignment
Reference: 1. Reasons for alignment of CPU memory access requirements 2. Resolution of memory alignment
If the src and dst addresses are not aligned, the read/write efficiency becomes lower.
The implementation of memcpy becomes more complex by implementing non-alignment copy through code, but affects the copy efficiency.
This non-alignment can be avoided in advance, becauseThe compiler allocates space to US based on memory alignment..
6. Optimize the copy data size
1. memcpy is called multiple times, but a small copy of data in Kb is copied each time.
In this case, branch prediction is minimized and the code is simplified.
2. Copy the memcpy Implementation of Mb
This affects the copy efficiency mainly in addressing.
Reference: It's okay to test memcpy.
7. Summary
Memcpy needs to be optimized as needed, such as the platform, processor, and copy size.