I was asked once during an interview to implement memcpy in C. The questions sounds simple first, but there is a lot to it actually. I think I did learn a lot by pointers and memory by researching this question. The code below shows 4 implementations of memcpy. The first one is the trivial implementation. The second one improves security by avoiding overwriting memory from the pointers. The third ones improves performance by copying one word at a time, instead of 1 bytes at a time. The fourth one copies a word at a time, and start copying with destination aligned to word byte boundary. The fifth one (TBD) copies with both source and destination aligned to word byte boundary.
#include <stdio.h>;
#include <string.h>;
#include <inttypes.h>;
void mymemcpy1(void *, const void *, size_t );
void mymemcpy2(void *, const void *, size_t );
void mymemcpy3(void *, const void *, size_t );
void mymemcpy4(void *, const void *, size_t );
int main(int argc, char **argv) {
char source[] = &quot;0123456789abdcdefghi&quot;; // 21 bytes (20 letters + '\0')
char dest[100];
// void * memcpy ( void * destination, const void * source, size_t num );
memcpy(dest, source, strlen(source) + 1);
printf(&quot;Source: %s. Destination: %s\n&quot;, source, dest);
strcpy(source, &quot;0123456789abdcdefghi&quot;);
mymemcpy1(dest, source, strlen(source) + 1);
printf(&quot;Source: %s. Destination: %s\n&quot;, source, dest);
strcpy(source, &quot;0123456789abdcdefghi&quot;);
mymemcpy2(dest, source, strlen(source) + 1);
printf(&quot;Source: %s. Destination: %s\n&quot;, source, dest);
strcpy(source, &quot;0123456789abdcdefghi&quot;);
mymemcpy3(dest, source, strlen(source) + 1);
printf(&quot;Source: %s. Destination: %s\n&quot;, source, dest);
strcpy(source, &quot;0123456789abdcdefghi&quot;);
mymemcpy4(dest, source, strlen(source) + 1);
printf(&quot;Source: %s. Destination: %s\n&quot;, source, dest);
return 0;
}
// simple implementation
void mymemcpy1(void *dest, const void *source, size_t num) {
int i = 0;
// casting pointers
char *dest8 = (char *)dest;
char *source8 = (char *)source;
printf(&quot;Copying memory %d byte(s) at a time\n&quot;, sizeof(char));
for (i = 0; i &lt; num; i++) {
dest8[i] = source8[i];
}
}
// it checks that destination array does not overwrite
// source memory
void mymemcpy2(void *dest, const void *source, size_t num) {
int i = 0;
// casting pointers
char *dest8 = (char *)dest;
char *source8 = (char *)source;
printf(&quot;Copying memory %d byte(s) at a time\n&quot;, sizeof(char));
for (i = 0; i &lt; num; i++) {
// make sure destination doesnt overwrite source
if (&amp;dest8[i] == source8) {
printf(&quot;destination array address overwrites source address\n&quot;);
return;
}
dest8[i] = source8[i];
}
}
// copies 1 word at a time (8 bytes at a time)
void mymemcpy3(void *dest, const void *source, size_t num) {
int i = 0;
// casting pointers
long *dest32 = (long *)dest;
long *source32 = (long *)source;
char *dest8 = (char *)dest;
char *source8 = (char *)source;
printf(&quot;Copying memory %d bytes at a time\n&quot;, sizeof(long));
for (i = 0; i &lt; num/sizeof(long); i++) {
if (&amp;dest32[i] == source32) {
printf(&quot;destination array address overwrites source address\n&quot;);
return;
}
dest32[i] = source32[i];
}
// copy the last bytes
i*=sizeof(long);
for ( ; i &lt; num; i++) {
dest8[i] = source8[i];
}
}
/* memory addres is n-byte aligned when address is multiple of n bytes
b-bit aligned is equivalent to b/8-byte aligned
padding = n - (offset &amp; ( -1)) = -offset &amp; (n-1)
aligned offset = (offset + n-1) &amp; ~(n-1)
Copies 8 bytes at a time with destination align to 64-byte boundary
*/
void mymemcpy4(void * dest, const void * source, size_t size) {
#define NBYTE 8 // n-byte boundary
int i = 0;
int j = 0;
// short and long pointers for copying 1 and 8 (sizeof(long))
// bytes at a time
long * destlong = (long *)dest;
long * sourcelong = (long *)source;
char * destshort = (char *)dest;
char * sourceshort = (char *)dest;
// copy first bytes until destination hits 64-byte boundary
while((((uintptr_t)&amp;destshort[i] &amp; (uintptr_t)(NBYTE-1)) != 0) &amp;&amp; \
(&amp;destshort[i] != source) &amp;&amp; (i &lt; size)) {
destshort[i] = sourceshort[i];
i++;
}
printf(&quot;%s: copied %d bytes up to %d-byte alignment\n&quot;,
__func__, i, NBYTE);
// now copy 8 (sizeof(long)) bytes at a time with dest aligned
// align destination pointer
destlong = ((uintptr_t)destlong + (NBYTE-1)) &amp; ~(uintptr_t)(NBYTE-1);
// continue copying where left off (we should align source as well...)
sourcelong = (long *)sourceshort;
// j+1 * 8 - 1 to avoid copying beyond last element in last iteration
while ((j+1)*sizeof(long) - 1 + i &lt; size &amp;&amp;\
&amp;destlong[j] &lt; (long *)source) {
destlong[j] = sourcelong[j];
j++;
}
printf(&quot;%s: copied %d bytes %d bytes at a time\n&quot;, __func__,
j*sizeof(long), sizeof(long));
// finally copy last bytes
i = i + j*sizeof(long);
int prev_i = i;
while(i &lt; size &amp;&amp; &amp;destshort[i] &lt; (char *)source) {
destshort[i] = sourceshort[i];
i++;
}
printf(&quot;%s: copied last %d bytes one at a time\n&quot;,
__func__, i-prev_i);
}
/* simpler implementation of mymemcpy4 */
void mymemcpy4b(const void * dest, void * src, size_t size) {
char * dest1 = (char *)dest;
char * src1 = (char *)src;
int n = 0;
#define NBYTE 64
// copy up to nbyte alignment
while ((((uintptr_t)dest1 & ~(NBYTE-1) != 0x00) && (n < size) {
*dest1++ = *src1++;
n++;
}
printf("copied %d bytes at a time up to %d bytes\n", sizeof(char), n);
// copy up to end minus last sizeof(long) bytes
long * dest2 = (long *)dest1;
long * src2 = (long *)src1;
while (n < size - sizeof(long)) {
*dest2++ = *src2++;
n+=sizeof(long);
}
printf("copied %d bytes at a time up to %d bytes\n", sizeof(long), n);
// copy last bytes
src1 = (char *)src2;
dest1 = (char *)dest2;
while (n < size) {
*dest1++ = *src1++;
n++;
}
printf("copied up to %d bytes\n", n);
}
The result is this:
Source: 0123456789abdcdefghi. Destination: 0123456789abdcdefghi
Copying memory 1 byte(s) at a time
Source: 0123456789abdcdefghi. Destination: 0123456789abdcdefghi
Copying memory 1 byte(s) at a time
Source: 0123456789abdcdefghi. Destination: 0123456789abdcdefghi
Copying memory 8 bytes at a time
Source: 0123456789abdcdefghi. Destination: 0123456789abdcdefghi
mymemcpy4: copied 0 bytes up to 64-byte alignment
mymemcpy4: copied 16 bytes 8 bytes at a time
mymemcpy4: copied last 5 bytes one at a time
Source: 0123456789abdcdefghi. Destination: 0123456789abdcdefghi
With mymemcpy4b:
./a.out
copied 1 bytes at a time up to 0 bytes
copied 8 bytes at a time up to 32 bytes
copied up to 40 bytes
src: 1234567890abcdefghi1234567890ABCDEFGHI
dest: 1234567890abcdefghi1234567890ABCDEFGHI
./a.out
copied 1 bytes at a time up to 16 bytes
copied 8 bytes at a time up to 32 bytes
copied up to 40 bytes
src: 1234567890abcdefghi1234567890ABCDEFGHI
dest: 1234567890abcdefghi1234567890ABCDEFGHI