最近我在一个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 }
这时再编译就不再有什么错误提示了,但运行之后的结果是这样子的:
乱码!
网上百度了一圈没有找到答案,然后google了一下国外网站,看到stackoverflow上有人也有同样的问题
http://stackoverflow.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 }
结果就正确了: