代码中经常用到 snprintf 函数,每次使用前都会 memset 一下缓冲区,感觉效率不高,今天突然想到是否真需要在使用前进行memset操作呢?
网络上找到的说法有些说不需要,有些说养成习惯。
我决定找找 snprintf 操作的本质,其身为传说中最安全的函数,必然有其道理。
#include#include #include /** len 大小不得大于 pData 缓冲区的大小,否则崩崩崩崩崩崩。。。。*/static int reprint(char *pData, int len){ if ((NULL == pData) || (0 >= len)) { return -1; } int j; printf("The data:"); for (j = 0; j < len; j++) { printf("%02x ", pData[j]); } printf("\n"); return 0;}int main(){ char dataPath[12] = {0}; memset(dataPath, '2', sizeof(dataPath)); printf("%d->%s <%d>\n", __LINE__, dataPath, strlen(dataPath)); reprint(dataPath, sizeof(dataPath)); snprintf(dataPath, sizeof(dataPath), "123455678"); printf("%d->%s <%d>\n", __LINE__, dataPath, strlen(dataPath)); reprint(dataPath, sizeof(dataPath)); snprintf(dataPath, sizeof(dataPath), "1234567890987654321"); printf("%d->%s <%d>\n", __LINE__, dataPath, strlen(dataPath)); reprint(dataPath, sizeof(dataPath)); snprintf(dataPath, strlen("22222"), "22222"); printf("%d->%s <%d>\n", __LINE__, dataPath, strlen(dataPath)); reprint(dataPath, sizeof(dataPath)); #if 0 snprintf(dataPath, strlen("1234567890987654321"), "1234567890987654321"); printf("%d->%s <%d>\n", __LINE__, dataPath, strlen(dataPath)); reprint(dataPath, sizeof(dataPath));#endif return 0;}
输出如下:
$ ./a.out 30->222222222222 <12>The data:32 32 32 32 32 32 32 32 32 32 32 32 /*(这是标志-> 打印1)*/31->123455678 <9>The data:31 32 33 34 35 35 36 37 38 00 32 32 /*(这是标志-> 打印2)*/35->12345678909 <11>The data:31 32 33 34 35 36 37 38 39 30 39 00 /*(这是标志-> 打印3)*/39->2222 <4>The data:32 32 32 32 00 36 37 38 39 30 39 00 /*(这是标志-> 打印4)*/
从输出结果中可得出几个结论:
1、snprintf 函数在格式化输出字串后面的会自动补'\0'
2、snprintf 在 buf 容量不足时会截断数据
3、snprintf 在容量充足的时候不会对后面的数据清零
另外,snprintf 第二个参数大小不能大于 第一个参数空间大小,不信可打开这段代码测试
#if 1 snprintf(dataPath, strlen("1234567890987654321"), "1234567890987654321"); printf("%d->%s <%d>\n", __LINE__, dataPath, strlen(dataPath)); reprint(dataPath, sizeof(dataPath));#endif
在 Linux 上运行会 core dump!
So,至于要不要每次在 snprintf 前使用 memset 清空缓冲区,就看实际需求了。
PS:从上面的结论可知:如果单单是字符串,可不用清空,提高效率。
还有一个疑问,第二个参数大于第一个参数的空间大小时会崩溃,那么这样还算不算安全函数呢?
但不管怎么说,只要程序员控制好第二个参数,这个函数相对其他函数还是非常安全的,值得推荐的!
我以前也用过sprintf,但是知道snprintf之后我就一直没用过sprintf,同事用 sprintf 我也会建议他用snprintf!