标题【C语言】vsnprintf函数的使用
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
`在学习stm32串口打印的时候遇到这个vsnprintf函数
unsigned char UsartPrintfBuf[296];
va_list ap;
unsigned char *pStr = UsartPrintfBuf;
va_start(ap, fmt);
vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap); //vsnprintf()格式化
va_end(ap);
一、vsnprintf是什么?
该函数是一个标准的 C 函数,用于格式化字符串并将生成的字符存储在缓冲区中。它与函数类似,但有一个关键区别:函数不是直接采用可变长度的参数列表,而是采用参数,该参数是已使用宏初始化的参数列表。
vsnprintf 函数的原型通常定义如下:
#include <stdio.h>
#include <stdarg.h>
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
str:指向一个字符数组的指针,该数组用于存储格式化的字符串。
size:str 指向的数组的大小(以字节为单位)。这是为了防止缓冲区溢出。
format:格式字符串,指定了后续参数如何被格式化为字符串。这个字符串遵循与 printf 相同的格式说明符。
ap:一个 va_list 类型的变量,它包含了要格式化的可变数量的参数。这个列表是通过 va_start 宏初始化的,并且可以通过 va_arg 宏来访问其中的参数。
返回值:
vsnprintf 函数返回写入的字符数(不包括终止的空字符 ‘\0’),但不包括由于缓冲区大小限制而未写入的字符数。如果发生错误,则返回负值。
使用 vsnprintf 的一个典型场景是当你需要从一个函数内部调用 printf 风格的函数,但这个函数需要接受一个可变的参数列表时。通过使用 va_list 和 vsnprintf,你可以构建一个灵活的函数,它能够处理任意数量和类型的参数。
然而,需要注意的是,由于 vsnprintf 需要你手动管理 va_list,因此它的使用相对于 snprintf 来说更为复杂和低级。在大多数情况下,如果你可以直接知道要格式化的参数,那么使用 snprintf 会更加简单和直接,比如下面的示例1的情况。
二、例子
1.示例1
代码如下(示例):
#include <stdio.h>
#include <stdarg.h>
void my_printf(char *str, ...) {
char buffer[100];
int len;
va_list args;
va_start(args, str);
len = vsnprintf(buffer, sizeof(buffer), str, args);
va_end(args);
printf("Result: %s, length: %d\n", buffer, len);
}
int main() {
my_printf("The answer is %d", 42);
my_printf("My name is %s and my age is %d", "Alice", 25);
return 0;
}
在这个例子中,我们定义了一个函数’my_printf(这需要一个格式字符串’strstr和可变数量的参数。在函数内部,我们声明了一个字符缓冲区 buffer大小为 100 字节,我们使用va_start()宏初始化一个 'VAva_list对象 'args’ 。
然后我们调用 'vsnprintf(使用三个参数:用于存储结果字符串的缓冲区buffer,缓冲区的最大大小(sizeof(buffer)),以及格式字符串str和va_list对象args.这允许我们将可变数量的参数传递给vsnprintf()使用 args对象。
在调用 va_end()宏来清理’参数args对象。
最后,在 'main()my_printf()两次不同设置字符串格式和参数列表。这第一次调用格式化整数值 42,以及第二次调用设置字符串格式"Alice"和整数值25.
当我们运行这个程序时,我们得到以下输出:
Result: The answer is 42, length: 16
Result: My name is Alice and my age is 25, length: 33
总结
vsnprintf函数用于将一组变长参数格式化为一个字符串,并将其存储到一个字符缓冲区buffer中。与sprintf()函数不同的是,vsnprintf()函数使用一个va_list参数,该参数包含要格式化的变长参数列表。这使得vsnprintf()函数更加灵活,可以根据需要在运行时传递变长参数列表,而不需要在编译时指定参数类型和数量。你可以传递4个,5个不同类型的参数,而且不用在函数定义的时候规定参数类型和数量。
虽然可以传递的参数数量有很多个,但也是有限制的,限制通常是由堆栈的大小或可用内存施加的,而不是由函数本身施加的。vsnprintf()
该函数接受可变数量的参数,这些参数通过对象传递给它。对象的大小由传递给它的参数的数量和大小决定va_list如果尝试将过多参数传递给vsnprintf() ,则可能会遇到堆栈溢出错误或内存不足。确切的限制将取决于平台和可用资源。
但是在实践中,很少遇到此限制,因为大多数程序不需要将大量参数传递给vsnprintf() 。如果您发现需要将大量参数传递给vsnprintf() ,则可能需要考虑重构代码以使用更节省内存的其他方法。