百篇大计敬本年之C语言巅峰之道《五》—— snprintf 是否需要 memset 缓冲区

    代码中经常用到 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!

转载于:https://my.oschina.net/bingwu/blog/1517682

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值