字符串拷貝函數(shù)memcpy和strncpy以及snprintf 的性能比較
問題:
函數(shù)memcpy(dest, src, sizeof(dest))、strncpy(dest, src, sizeof(dest))和snprintf(dest, sizeof(dest), "%s", src)都可以將src字符串中的內(nèi)容拷貝到dest字符串中。
哪一種方式效率最高呢?
就是說,哪種方式性能最好呢?
解決辦法:
1. 建立三個(gè)文件test_memcpy.c,test_strncpy.c和test_snprintf.c:
文件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;
}
文件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;
}
文件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. 分別編譯三個(gè)文件:
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. 沒有優(yōu)化的情況下不同函數(shù)消耗時(shí)間對(duì)比:
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$
從上面運(yùn)行結(jié)果可以看出:沒有任何優(yōu)化的情況下,memcpy()和strncpy()性能相差4倍,snprintf()和strncpy()性能相差約2.5倍。
4.采用O3優(yōu)化情況下不同函數(shù)消耗時(shí)間對(duì)比:
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$
從上面運(yùn)行結(jié)果可以看出:采用O3優(yōu)化后,memcpy()和strncpy()性能相差近5倍,snprintf()和strncpy()性能相差基本不變約2.5倍。
5. 性能對(duì)比結(jié)論:
在需要用到字符串拷貝函數(shù)的時(shí)候,永遠(yuǎn)不要使用strncpy(),無論什么時(shí)候都用snprintf()來代替,而memcpy()是性能更好的實(shí)現(xiàn)方式。
strlen+memcpy也是linux內(nèi)核的實(shí)現(xiàn)方式。
6. 意外收獲結(jié)論:
將上述三個(gè)文件中的memset()改為用bzero()來實(shí)現(xiàn)數(shù)組的清零操作。
使用O3來進(jìn)行優(yōu)化,三個(gè)函數(shù)的耗時(shí)時(shí)間如下:
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$
結(jié)論:僅僅換了一個(gè)清零函數(shù),使得memcpy()和strncpy()的性能差別達(dá)到約12倍,而snprintf()和strncpy()的性能差別也達(dá)到約4倍。
就清零操作來說,bzero()遠(yuǎn)比memset()更高效。
相關(guān)文章
C語言實(shí)現(xiàn)linux網(wǎng)卡連接檢測的方法
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)linux網(wǎng)卡連接檢測的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
OpenGL實(shí)現(xiàn)不規(guī)則區(qū)域填充算法
這篇文章主要為大家詳細(xì)介紹了OpenGL實(shí)現(xiàn)不規(guī)則區(qū)域填充算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
C++右值引用與move和forward函數(shù)的使用詳解
為了支持移動(dòng)操作,新標(biāo)準(zhǔn)引入了一種新的引用類型——右值引用(rvalue reference)。所謂右值引用就是必須綁定到右值的引用,這篇文章主要介紹了C++右值引用與move和forward的使用2022-08-08
C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索
這篇文章主要為大家介紹了C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10

