如何把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++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】
STL实践与分析 --初窥算法[下] 一.写容器元素的算法 一些算法写入元素值.在使用这些算法写元素时一定要当心.必须.写入输入序列的元素 写入到输入序列的算法本质上是安全的--仅仅会写入与指定输入范 ...
- Android采用canvas绘制各种图形
canvas通俗的说就是一个帆布,我们可以用刷子paint,就此随机抽签显卡. 原理: 能够canvas视Surface替代或接口.图形绘制Surface向上.Canvas封装了全部的绘制调用. 通过 ...
- POSIX 螺纹具体解释(1-概要)
线程是有趣的 线程类似于进程.如同进程,线程由内核按时间分片进行管理.在单处理器系统中,内核使用时间分片来模拟线程的并发运行.这样的方式和进程的同样. 而在多处理器系统中,如同多个进程.线程实际上一样 ...
- Android开发在路上:少去踩坑,多走捷径(转)
最近一朋友提了几个Android问题让我帮忙写个小分享,我觉得对新人还是挺有帮助的,所以有了这个小分享. 1. 目前, Android APP开发完成后,通常需要在哪些机型上进行测试? 2. 目前, ...
- 漂浮广告代码兼容ie、firefox,多个漂浮不冲突,调用只需两行代码
原文:漂浮广告代码兼容ie.firefox,多个漂浮不冲突,调用只需两行代码 将广告内容放在div中,设置一个id,然后用下面方法调用var adcls=new AdMove("div的id ...
- Linux网络编程——连接和面向连接的协议之间没有区别
网络编程中最重要的概念就是连接取向(connection-oriented)和无连接(connectionless)协议.虽然本质.两者之间的区别是不难理解,编程的人来说,却是个非常easy混淆的问题 ...
- oracle rac常用的命令
oracle rac常用的命令 节点层:olsnodes 网络层: oifcfg 集群层:crsctl,ocrcheck,ocrdump,ocrconfig 应用层:srvctl,onsctl,crs ...
- 转让lua性能executeGlobalFunction
没有其他的,搞搞cocos2dx的lua文字,话lua这件事情在几年前学过一段时间.还曾对自己c++介面,我已经做了一些小东西.只是时间的流逝,模糊记忆. 拿起点功夫和成本.下面是我的一些经验. co ...
- 经典算法题每日演练——第六题 协同推荐SlopeOne 算法
原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法 相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,“商品推荐”,"猜你喜欢“,在实体店中我们有导购来为 ...
- Java设计模式菜鸟系列(四)工厂方法模式建模与实现
转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39760895 工厂方法模式(Factory Method) 工厂方法:顾名思义,就是调用工 ...