如何把va_list可变参数传送到下一级函数中(如传送到printf)

时间:2022-01-21 21:41:38

最近我在一个LCD上想实现打印格式化字符串的功能,实现这样的功能可有两种方式:

一 最直接的就是自己去解析类似于printf功能的一个函数;

二 比较简单的方法是使用已有的sprintf功能,把格式化字符串打印到一个字符缓冲区中,再将这个字符缓冲区打印到LCD上来。

这里选择了第二种方法!

我已经把这个嵌入式程序弄到pc机上来运行了,第一次编写的代码是这样子的:

 1 #include <stdio.h>
 2 #include <stdarg.h>
 3 
 4 void lcm_appendf(const char *fmt, ...)
 5 {
 6     char fm_buffer[128];
 7     int fm_len = 0;
 8     fm_len = snprintf(fm_buffer, 128, fmt);
 9     
10     printf("fm_len = %d\r\n", fm_len);
11     printf("%s", fm_buffer);
12 }
13 
14 int main(int argc, char **args)
15 {
16     char c;
17     
18 //    printf("Hello, this is Merlin Dec:%d, Hex:0x%x, Str:%s\r\n", 254, 0x32, "tfAna");
19     lcm_appendf("Hello, this is Merlin Dec:%d, Hex:%x, Str:%s\r\n", 254, 0x32, "tfAna");
20     scanf("%c", &c);
21 }

编译时提示错误:

$ gcc lcm_appendf.c
lcm_appendf.c: In function ‘lcm_appendf’:
lcm_appendf.c:8:2: warning: format not a string literal and no format arguments [-Wformat-security]
lcm_appendf.c:8:2: warning: format not a string literal and no format arguments [-Wformat-security]

表示没有格式参数!原来我忘记把格式(%d%x%s)对应的参数(254 0x32 "tfAna")写上去。所以先加上,这些可变参数,就是lcm_appendf的“第二个参数”...

直接写成snprintf(fm_buffer, 128, fmt, ...)显然是不行的!那么我怎么把lcm_appendf中的...转化为snprintf可以接受的参数呢?答案是使用va_list这个可变参数类型。

所以修改后的代码变成这样子:

 1 #include <stdio.h>
 2 #include <stdarg.h>
 3 
 4 void lcm_appendf(const char *fmt, ...)
 5 {
 6     char fm_buffer[128];
 7     int fm_len = 0;
 8     va_list ap;
 9     
10     va_start(ap, fmt);
11     fm_len = snprintf(fm_buffer, 128, fmt, ap);
12     va_end(ap);
13     
14     printf("fm_len = %d\r\n", fm_len);
15     printf("%s", fm_buffer);
16 }
17 
18 int main(int argc, char **args)
19 {
20     char c;
21     
22 //    printf("Hello, this is Merlin Dec:%d, Hex:0x%x, Str:%s\r\n", 254, 0x32, "tfAna");
23     lcm_appendf("Hello, this is Merlin Dec:%d, Hex:%x, Str:%s\r\n", 254, 0x32, "tfAna");
24     scanf("%c", &c);
25 }

这时再编译就不再有什么错误提示了,但运行之后的结果是这样子的:

如何把va_list可变参数传送到下一级函数中(如传送到printf)

乱码!

网上百度了一圈没有找到答案,然后google了一下国外网站,看到*上有人也有同样的问题

http://*.com/questions/5977326/call-printf-using-va-list

原来,得使用vprintf啊!对应于我这里就是使用vsnprintf了。(参考这个函数的用法http://en.cppreference.com/w/cpp/io/c/vfprintf

再修改源码为:

 1 #include <stdio.h>
 2 #include <stdarg.h>
 3 
 4 void lcm_appendf(const char *fmt, ...)
 5 {
 6     char fm_buffer[128];
 7     int fm_len = 0;
 8     va_list ap;
 9     
10     va_start(ap, fmt);
11     fm_len = vsnprintf(fm_buffer, 128, fmt, ap);
12     va_end(ap);
13     
14     printf("fm_len = %d\r\n", fm_len);
15     printf("%s", fm_buffer);
16 }
17 
18 int main(int argc, char **args)
19 {
20     char c;
21     
22 //    printf("Hello, this is Merlin Dec:%d, Hex:0x%x, Str:%s\r\n", 254, 0x32, "tfAna");
23     lcm_appendf("Hello, this is Merlin Dec:%d, Hex:%x, Str:%s\r\n", 254, 0x32, "tfAna");
24     scanf("%c", &c);
25 }

结果就正确了:

如何把va_list可变参数传送到下一级函数中(如传送到printf)