snprintf函数是C语言中非常常用的一个函数,它的作用是格式化一段文本放到指定的缓存中。和它类似的还有sprintf,vsnprintf等。它们都完成类似的功能,但又有些区别,如sprintf是不会检查输出缓存的长度的,需要调用者确保长度是足够的。vsnprintf函数和snprintf很像,但它是通过valist来传入格式化参数,所以一般用于传入了可变的需要格式化字符串的函数内。而我们最常用的就是snprintf了,因为它具有缓冲区的溢出保护。 snprintf函数的原型如下:intsnprintf(charstr,sizetsize,constcharformat,。。。); 其中:str传入输出缓冲区的地址;size指出输出缓冲区的大小;format为传入的格式化字符串;其后的参数就是格式化的参数了。 该函数返回一个整数,表示格式化后的文本大小。通过这个返回值,我们可以做很多事情。也正是对这个返回值的理解不够或者使用错误,我们往往会踩一些坑。 最普通的用法是使用该函数来格式化一段文本,如:charszText〔1024〕;inta10,b20;snprintf(szText,sizeof(szText),ddd,a,b,ab); 该函数具有缓冲区保护的功能,如果格式化输出内容超过了缓冲区的最大长度,那么输出字符串会被截断到缓冲区的最大长度。同时无论如何,字符串最后的结尾‘’是一定会有的,保证了输出的字符串不会溢出。所以这也是广大程序员喜欢使用这个函数的原因。 如果我们需要格式化一个具有多个元素的数组,那么这个时候就可以充分利用snprintf的返回值了。我们只需要反复调用snprintf并移动缓冲区的起始位置就能实现。代码如下:charszText〔1024〕;输出的缓冲区inta〔100〕{。。。};假设会有代码逻辑填充这个数组的内容循环数组的下标intlensnprintf(szText,sizeof(szText),a{);保存输出字符串的长度for(n0;n100;n){lensnprintf(szTextlen,sizeof(szText)len,d,,a〔n〕);}lensnprintf(szTextlen,sizeof(szText)len,}); 这段代码看起来能正常工作,通常也确实可以正常工作,但是前提条件是szText的缓冲区大小是足够大的。如果缓冲区的大小不够会发生什么情况?你不妨改小szText再试试。 那么为什么会出现问题呢?首先我们要深入理解一下snprintf返回值的含义。按前面所述,返回值表示格式化后文本的大小,注意不是返回输出缓冲内的字符串长度。什么意思呢,也就是说,如果输出的缓冲足够大,大到可以容纳所有的输出文本,那么这个返回的长度恰恰就是输出缓存中的字符串长度。如果输出缓冲不够大,或者根本就没有传入输出缓冲这个参数呢?返回值就和实际的输出文本长度不一样了。为什么是这样?其实这个函数本来也是可以用来计算格式化所需要的最小缓存大小,并根据返回值来实际分配输出缓冲的内存。如下代码所示的用法:inta10;intb20;charpszOutNULL;输出缓存指针lensnprintf(NULL,0,ddd,a,b,ab);计算需要的输出长度。pszOut(char)alloca(len1);需要考虑结尾的0战用一个字符snprintf(pszOut,len1,ddd,a,b,ab); 有人会疑惑,为什么需要这样写?上面这个例子可能不明显。但是如果需要格式化的内容不固定,长度变化范围很大。那么就有可能不太好使用固定大小的缓冲。 理解了这个返回值的含义和用法,再回到上面那个循环调用的例子。我们需要加上对长度的校验就没有问题了:charszText〔1024〕;输出的缓冲区inta〔100〕{。。。};假设会有代码逻辑填充这个数组的内容循环数组的下标intlensnprintf(szText,sizeof(szText),a{);保存输出字符串的长度for(n0;n100lensizeof(szText);n){lensnprintf(szTextlen,sizeof(szText)len,d,,a〔n〕);}lensnprintf(szTextlen,sizeof(szText)len,}); 如果有什么疑问,欢迎一起讨论。