String copy function memcpy and strncpy and snprintf performance comparison

  • 2020-04-02 01:11:22
  • OfStack

Question:
The functions memcpy(dest, SRC, sizeof(dest)), strncpy(dest, SRC, sizeof(dest)), and snprintf(dest, sizeof(dest), "%s", SRC) can all copy the contents of the SRC string into the dest string.
Which is the most efficient way?
That is, what works best?
Solutions:
1. Create three files test_memcpy.c, test_strncpy.c and test_snprintf.c:
File test_memcpy. C:


david@u1110-hp:~/wrk/tmp/cstring$ cat test_memcpy.c
#include <string.h>
int main(){
 char src[] = "1234567890";
 char dest[2048];
 int len = 0;
 for(int i = 0; i < 10000000; ++i){
  memset(dest, 0, sizeof(dest));
  len = strlen(src);
  len = sizeof(dest) - 1 > len? len: sizeof(dest) -1;
  memcpy(dest, src, len);
  dest[len] = '0';
 }
 return 0;
}

File test_strncpy. C:

#include <string.h>
int main() {
 char src[] = "1234567890";
 char dest[2048];
 int len = 0;

 for(int i = 0; i < 10000000; ++i) {
  memset(dest, 0, sizeof(dest));
  strncpy(dest, src, sizeof(dest));
 }

 return 0;
}

File test_snprintf. C:

#include <stdio.h>
#include <string.h>
int main() {
 char src[] = "1234567890";
 char dest[2048];
 int len = 0;

 for(int i = 0; i < 10000000; ++i) {
  memset(dest, 0, sizeof(dest));
  snprintf(dest, sizeof(dest), "%s", src);
 }

 return 0;
}

2. Compile three files respectively:

david@u1110-hp:~/wrk/tmp/cstring$ gcc -std=c99 -o test_memcpy test_memcpy.c
david@u1110-hp:~/wrk/tmp/cstring$ gcc -std=c99 -o test_strncpy test_strncpy.c
david@u1110-hp:~/wrk/tmp/cstring$ gcc -std=c99 -o test_snprintf test_snprintf.c

3. Comparison of consumption time of different functions without optimization:

david@u1110-hp:~/wrk/tmp/cstring$ time ./test_strncpy
real 0m16.472s
user 0m16.309s
sys 0m0.036s
david@u1110-hp:~/wrk/tmp/cstring$ time ./test_snprintf 
real 0m6.106s
user 0m6.100s
sys 0m0.000s
david@u1110-hp:~/wrk/tmp/cstring$ time ./test_memcpy 
real 0m4.179s
user 0m4.144s
sys 0m0.000s
david@u1110-hp:~/wrk/tmp/cstring$

As you can see from the above results, without any optimization, the performance difference between memcpy() and strncpy() is 4 times, and the performance difference between snprintf() and strncpy() is about 2.5 times.

4. Comparison of consumption time of different functions under O3 optimization:


david@u1110-hp:~/wrk/tmp/cstring$ gcc -std=c99 -O3 -o test_snprintf test_snprintf.c
david@u1110-hp:~/wrk/tmp/cstring$ gcc -std=c99 -O3 -o test_strncpy test_strncpy.c
david@u1110-hp:~/wrk/tmp/cstring$ gcc -std=c99 -O3 -o test_memcpy test_memcpy.c
david@u1110-hp:~/wrk/tmp/cstring$


david@u1110-hp:~/wrk/tmp/cstring$ time ./test_strncpy
real 0m16.178s
user 0m16.161s
sys 0m0.000s
david@u1110-hp:~/wrk/tmp/cstring$ time ./test_snprintf 
real 0m6.242s
user 0m6.032s
sys 0m0.056s
david@u1110-hp:~/wrk/tmp/cstring$ time ./test_memcpy 
real 0m3.567s
user 0m3.436s
sys 0m0.012s
david@u1110-hp:~/wrk/tmp/cstring$

It can be seen from the above results that after O3 optimization, the performance difference between memcpy() and strncpy() is nearly 5 times, and the performance difference between snprintf() and strncpy() is basically unchanged about 2.5 times.

5. Conclusion of performance comparison:
Never use strncpy() when you need to use a string copy function, always use snprintf() instead, and memcpy() is a better implementation.
Strlen +memcpy is also the implementation of the Linux kernel.

6. Serendipity conclusion:
Change the memset() in the above three files to use bzero() for array zeroing.
Using O3 for optimization, the time of the three functions is as follows:

david@u1110-hp:~/wrk/tmp/cstring$ time ./test_strncpy
real 0m14.395s
user 0m13.929s
sys 0m0.092s
david@u1110-hp:~/wrk/tmp/cstring$ time ./test_snprintf 
real 0m3.785s
user 0m3.772s
sys 0m0.000s
david@u1110-hp:~/wrk/tmp/cstring$ time ./test_memcpy 
real 0m1.241s
user 0m1.236s
sys 0m0.004s
david@u1110-hp:~/wrk/tmp/cstring$

Conclusion: simply changing the zeroing function results in a performance difference of about 12 times between memcpy() and strncpy(), and about 4 times between snprintf() and strncpy().
Bzero () is far more efficient than memset() for zeroing operations.


Related articles: