最近我在一个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)的更多相关文章

  1. 【转载】va_list 可变参数 简介 va_copy vprintf

    [说明]本文转载自 smart 的文章 http://blog.sina.com.cn/s/blog_590be5290100qhxr.html  及百度百科 va_list是一个宏,由va_star ...

  2. va_list可变参数

    可变参数函数实现 va_list,va_start,va_arg,va_end va可变参数意思,variable-argument. 1. 头文件及实现 linux中定义在gcc头文件中,stdar ...

  3. js求和运算在可变参数的情况下ES3、ES5和ES6的写法区别

    //ES3.ES5的写法 function foo(){ var arr = Array.prototype.slice.call(arguments); var sum = 0; arr.forEa ...

  4. C++ 11可变参数接口设计在模板编程中应用的一点点总结

    概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...

  5. volatile,可变参数,memset,内联函数,宽字符窄字符,国际化,条件编译,预处理命令,define中##和#的区别,文件缓冲,位域

    1.volatile: 要求参数修改每次都从内存中的读取.这种情况要比普通运行的变量需要的时间长. 当设置了成按照C99标准运行之后,使用volatile变量之后的程序运行的时间将比register的 ...

  6. String filePath = request.getSession().getServletContext().getRealPath("/");这句话返回的路径是什么,解释下getRealPath("/")函数中的"/"表示什么意思

    request.getSession().getServletContext() 获取的是Servlet容器对象,相当于tomcat容器了.getRealPath("/") 获取实 ...

  7. MySQL下concat函数中null值问题

    在mysql中,使用CONCAT(str1,str2,...)函数拼接字符串的过程中,如果你拼接的字段当中有值为null,那么拼接的结果就为null 注: select CONCAT(字段1,字段2) ...

  8. 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...

  9. C语言可变参数va_list

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,-) int ...

随机推荐

  1. 学习笔记之TCP/IP协议的重要性

    1. 随处可见的协议     在计算机网络与信息通信领域里,人们常常提及"协议"一词.互联网中常 用的具有代表性的协议有IP.TCP.HITP等. 而LAN(局域网)中经常使用的协 ...

  2. Arcgis for Javascript之featureLayer图和属性互操作性

    说明:主要实现加载FeatureLayer并显示属性表,而要实现联动属性表与地图,首先,看看实施后的效果: 显示效果 如上图所看到的,本文章主要实现了下面几个功能:1.FeatureLayer属性表的 ...

  3. 图widget--jqplot样品和参数描述的简单演示

    最简单的线图 第一步:引入必要的CSS.JS文件 <link rel="stylesheet" type="text/css" href="js ...

  4. Word2vec 讨论

    我没有在自然语言处理完成.但基于Deep Learning 关注,自然知道一些Word2vec强大. Word2vec 是google 在2013年提供的一款将词表征为实数值向量的高效工具.而Word ...

  5. poj3417 Network 树形Dp+LCA

    题意:给定一棵n个节点的树,然后在给定m条边,去掉m条边中的一条和原树中的一条边,使得树至少分为两部分,问有多少种方案. 神题,一点也想不到做法, 首先要分析出加入一条边之后会形成环,形成环的话,如果 ...

  6. Linux经常使用的命令-权利管理命令-权利管理命令chmod

    指令名字:chmod 命令英语的意图:change the permissions mode of a file 凡路径命令:/bin/chmod 语法:chmod [{ugoa}{+-=}{rwx} ...

  7. Nagios显示器MySQL一个错误:NRPE: Unable to read output具体的解决过程

    前言:nagios介面.见监测mysql服务错误,如下面: Warning:NRPE: Unable to read output 1,跟nagios显示器server上check下 1.1.运行ch ...

  8. 深入了解setInterval方法

    相信大家对setInterval方法肯定非常熟悉,但不少人对其缺乏深入的了解,致使当一个flash里有多个setInterval的时候就容易混淆,该清除的间隔lID没有清除,不该清除的时候却清除了.对 ...

  9. CII-2.4指针常量和常量指针

    #define T Stack_T typedef struct T *T; struct T { int count; struct elem { void *x; struct elem *lin ...

  10. enq: SQ - contention

    --每分钟操作 SQL> select  sql_id, mi, count(mi)   2    from (select event, sql_id, to_char(sample_time ...