程序中经常会涉及到字符串拷贝操作,常见的字符串拷贝方法有:strncpy、snprintf、memcpy、strlen+memmove、strcpy、sprintf、、bcopy等。strcpy、sprintf就不讨论了,由于容易引入目标缓冲区溢出、不能有效保证尾部/0等问题,在实际工程项目中很少使用—如果不怕被坑的同学们可以尝试下,多踩坑才能加深记忆。
之前看过别人的总结,在目标缓冲区较大、实际待拷贝字符串较短时,strncpy性能比较差,snprintf性能较好,memcpy性能也很差,所以一般推荐采用snprintf的方式进行字符串拷贝。
本着实事求是的原则,同时加深自己的理解,实际测了下,性能对比如下:
循环次数:100000 目标缓冲区长度:1024*1024 源字符串长度:16
耗时: memcpy:7337ms,strncpy:4254ms, snprintf: 12.7ms
【三者已经明显拉开距离了,一目了然】
snprintf code起来比较简单,效率有保证。
从三个case来看,无论在性能、编码复杂度上snprintf都完胜strncpy。
因此在实际code中,strncpy往往是比较忌讳的,容易引起性能瓶颈,而且实在找不出不以snprintf替换它的理由,后续字符串操作尽量用snprintf替换strncpy。
程序中涉及字符串操作部分,往往是敏感地带,因为稍不留神就会出现缓冲区溢出, 或处理完后目标串不能保证以/0结尾(如果真的引入这种问题,那后面程序很容易产生core dump、crash),名字带‘n‘的函数一般可以防止目标缓冲区写溢出,那是否也可以保证缓冲区以/0结尾呢?汇总如下(其实随便一个讲c lib库函数地方都有说明):
strncpy: 如果src的前n个字节不含NULL字符,则结果不会以NULL字符结束。
如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。所以strncpy完了,尽量自己补/0。
snprintf: 始终保证以/0结尾,即最多copy n-1个有效字符,可放心用。
fgets : 最多读入n-1个字符,始终保证以/0结尾,可放心用。
字符串拷贝函数测试用例代码及数据如下: