代码中经常用到 snprintf 函数,每次使用前都会 memset 一下缓冲区,感觉效率不高,今天突然想到是否真需要在使用前进行memset操作呢?
网络上找到的说法有些说不需要,有些说养成习惯。
我决定找找 snprintf 操作的本质,其身为传说中最安全的函数,必然有其道理。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* 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!