如何把va_list可变参数传送到下一级函数中(如传送到printf)
最近我在一个LCD上想实现打印格式化字符串的功能,实现这样的功能可有两种方式:
一 最直接的就是自己去解析类似于printf功能的一个函数;
二 比较简单的方法是使用已有的sprintf功能,把格式化字符串打印到一个字符缓冲区中,再将这个字符缓冲区打印到LCD上来。
这里选择了第二种方法!
我已经把这个嵌入式程序弄到pc机上来运行了,第一次编写的代码是这样子的:
#include <stdio.h>
#include <stdarg.h> void lcm_appendf(const char *fmt, ...)
{
char fm_buffer[];
int fm_len = ;
fm_len = snprintf(fm_buffer, , fmt); printf("fm_len = %d\r\n", fm_len);
printf("%s", fm_buffer);
} int main(int argc, char **args)
{
char c; // printf("Hello, this is Merlin Dec:%d, Hex:0x%x, Str:%s\r\n", 254, 0x32, "tfAna");
lcm_appendf("Hello, this is Merlin Dec:%d, Hex:%x, Str:%s\r\n", , 0x32, "tfAna");
scanf("%c", &c);
}
编译时提示错误:
$ gcc lcm_appendf.c
lcm_appendf.c: In function ‘lcm_appendf’:
lcm_appendf.c::: warning: format not a string literal and no format arguments [-Wformat-security]
lcm_appendf.c::: warning: format not a string literal and no format arguments [-Wformat-security]
表示没有格式参数!原来我忘记把格式(%d%x%s)对应的参数(254 0x32 "tfAna")写上去。所以先加上,这些可变参数,就是lcm_appendf的“第二个参数”...
直接写成snprintf(fm_buffer, , fmt, ...)显然是不行的!那么我怎么把lcm_appendf中的...转化为snprintf可以接受的参数呢?答案是使用va_list这个可变参数类型。
所以修改后的代码变成这样子:
#include <stdio.h>
#include <stdarg.h> void lcm_appendf(const char *fmt, ...)
{
char fm_buffer[];
int fm_len = ;
va_list ap; va_start(ap, fmt);
fm_len = snprintf(fm_buffer, , fmt, ap);
va_end(ap); printf("fm_len = %d\r\n", fm_len);
printf("%s", fm_buffer);
} int main(int argc, char **args)
{
char c; // printf("Hello, this is Merlin Dec:%d, Hex:0x%x, Str:%s\r\n", 254, 0x32, "tfAna");
lcm_appendf("Hello, this is Merlin Dec:%d, Hex:%x, Str:%s\r\n", , 0x32, "tfAna");
scanf("%c", &c);
}
这时再编译就不再有什么错误提示了,但运行之后的结果是这样子的:
乱码!
网上百度了一圈没有找到答案,然后google了一下国外网站,看到stackoverflow上有人也有同样的问题
http://stackoverflow.com/questions/5977326/call-printf-using-va-list
原来,得使用vprintf啊!对应于我这里就是使用vsnprintf了。(参考这个函数的用法http://en.cppreference.com/w/cpp/io/c/vfprintf)
再修改源码为:
#include <stdio.h>
#include <stdarg.h> void lcm_appendf(const char *fmt, ...)
{
char fm_buffer[];
int fm_len = ;
va_list ap; va_start(ap, fmt);
fm_len = vsnprintf(fm_buffer, , fmt, ap);
va_end(ap); printf("fm_len = %d\r\n", fm_len);
printf("%s", fm_buffer);
} int main(int argc, char **args)
{
char c; // printf("Hello, this is Merlin Dec:%d, Hex:0x%x, Str:%s\r\n", 254, 0x32, "tfAna");
lcm_appendf("Hello, this is Merlin Dec:%d, Hex:%x, Str:%s\r\n", , 0x32, "tfAna");
scanf("%c", &c);
}
结果就正确了:
如何把va_list可变参数传送到下一级函数中(如传送到printf)的更多相关文章
- 【转载】va_list 可变参数 简介 va_copy vprintf
[说明]本文转载自 smart 的文章 http://blog.sina.com.cn/s/blog_590be5290100qhxr.html 及百度百科 va_list是一个宏,由va_star ...
- va_list可变参数
可变参数函数实现 va_list,va_start,va_arg,va_end va可变参数意思,variable-argument. 1. 头文件及实现 linux中定义在gcc头文件中,stdar ...
- js求和运算在可变参数的情况下ES3、ES5和ES6的写法区别
//ES3.ES5的写法 function foo(){ var arr = Array.prototype.slice.call(arguments); var sum = 0; arr.forEa ...
- C++ 11可变参数接口设计在模板编程中应用的一点点总结
概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...
- volatile,可变参数,memset,内联函数,宽字符窄字符,国际化,条件编译,预处理命令,define中##和#的区别,文件缓冲,位域
1.volatile: 要求参数修改每次都从内存中的读取.这种情况要比普通运行的变量需要的时间长. 当设置了成按照C99标准运行之后,使用volatile变量之后的程序运行的时间将比register的 ...
- String filePath = request.getSession().getServletContext().getRealPath("/");这句话返回的路径是什么,解释下getRealPath("/")函数中的"/"表示什么意思
request.getSession().getServletContext() 获取的是Servlet容器对象,相当于tomcat容器了.getRealPath("/") 获取实 ...
- MySQL下concat函数中null值问题
在mysql中,使用CONCAT(str1,str2,...)函数拼接字符串的过程中,如果你拼接的字段当中有值为null,那么拼接的结果就为null 注: select CONCAT(字段1,字段2) ...
- 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)
一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...
- C语言可变参数va_list
一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,-) int ...
随机推荐
- 【C疯狂的教材】(四)C语言分支语句
1.程序的结构 程序默认从上到下顺序运行(顺序结构) 程序的结构:顺序结构.分支结构.循环结构 2.if分支语句 程序运行的过程中能够有多个选择 格式: if(表达式){ 语句块; } ...... ...
- extjs每一个组件要设置唯一的ID
extjs每一个组件要设置唯一的ID,否则会造成各种错误 EXTJS基本上是靠ID来识别组件的,假如你在panel1中有个ID:"keyword"的textfield,而panel ...
- Android四种Activity的加载模式(转)
建议首先阅读下面两篇文章,这样才可以更好的理解Activity的加载模式: Android的进程,线程模型: http://www.cnblogs.com/ghj1976/archive/2011/0 ...
- 翻译器DIY它———算在英文文本中的单词数,字符和行数
咳咳.这部分应该是序列化编译器DIY的,然而,在这样做DIY第一次使用前flex 为了练练手,对于后者的理解是有帮助. 在word 我经常看到一个字计数功能,因此,它是如何实现,当然,首先想到的是要经 ...
- angularjs从零开始(一)
简介 AngularJS是为了克服HTML在构建应用上的不足而设计的.HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了.所以我做了一些工作(你也可以觉得是小 ...
- js中的open和showModalDialog
一.window.open()支持环境: JavaScript1.0+/JScript1.0+/Nav2+/IE3+/Opera3+ 二.基本语法:window.open(pageURL,name,p ...
- asp.net学习之 数据绑定控件--List数据绑定控件
原文:asp.net学习之 数据绑定控件--List数据绑定控件 List控件(如 CheckBoxList.DropDownList.ListBox 和 RadioButtonList 类)继承自L ...
- Microservice架构模
Microservice架构模 在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices& ...
- Js 对象添加属性
var arr = new Array(); arr[0] = jQuery("#data1").val(); var obj = {}; obj.y='abc'; arr.pus ...
- 第8章 装饰模式(Decorator Pattern)
原文 第8章 装饰模式(Decorator Pattern) 概述: 装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. ...