C语言的自学渐渐接近尾声,今天学到了标准库中的stdarg.h头,里面关联了stdio.h头里面的一类函数:v...printf函数,里面举的例子看了之后还是不太明白,google了一下依旧不是很懂,所以自行测试了一下,以下是过程:

这一类函数书中列举了四个,原型分别有:

int vfprintf(FILE *restrict stream, const char * restrict format, va_list arg);

int vprintf(const char * restrict format, va_list arg);

int vsnprintf(char * restrict s, size_t n, const char * restrict format, va_list arg);

int vsprintf(char * restrict s, const char * restrict format, va_list arg);

书中用vfprintf函数举例:

假设程序需要不时地显示出错消息,而且我们希望每条消息都以以下格式的前缀开始:

** Error n:

这里的n在显示第一条出错消息的时候是1,以后每显示一条错误消息增加1。为了使产生出错消息更加容易,我们将编写一个名为errorf的函数。此函数类似于printf函数,但是它总在输出的开始添加了** Error n:,并且总是向stderr而不是stdout输出。errorf函数将调用vfprintf函数来完成大部分实际输出工作。下面是errorf函数可能的写法:

int errorf(const char *format, ...)
{
static int num_errors = ;
int n;
va_list ap; num_errors++;
fprintf(stderr, "** Error %d: ", num_errors);
va_start(ap, format);
n = vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, "\n");
return n;
}

看完例子之后我依然不知道这个函数究竟有什么作用,于是我google了一下,发现了一个网站举了这样一个例子:

/* vfprintf example */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> /* functions */
void inputError(char *function, char *format, ...); /* main */
int main(void) {
int sex, age; /* 输入性别 */
puts("请输入性別:(1:男性 2:女性)");
scanf("%d", &sex);
if ( sex != && sex != ) {
inputError("main", "性别是1或2!(输入值: %d)\n", sex);
return EXIT_FAILURE;
} /* 输入年龄 */
puts("请输入年龄:");
scanf("%d", &age);
if ( age < || age > ) {
inputError("main", "年龄范围[0,150]!(输入值: %d)\n", age);
return EXIT_FAILURE;
} return EXIT_SUCCESS;
} /**
* @brief 错误处理
* @param[IN] function 函数名
* @param[IN] format 格式化字符串
* @param[IN] ... 可变长参数
*/
void inputError(char *function, char *format, ...) {
va_list arg;
va_start(arg, format); fprintf(stderr, "发生错误的函数: %s\n", function); /* 显示错误信息 */
vfprintf(stderr, format, arg); va_end(arg);
}

执行结果:

请输入性別:(1:男性 2:女性)

3

发生错误的函数: main

性别是1或2!(输入值: 3)

我看完例子之后有点模模糊糊的感觉了,难道说这类函数是将调用它们的函数的可变参数列表转化为自己的可变参数列表,然后通过格式匹配将这些参数输出到流中的?

于是我自己写了个小函数测试一下:

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h> int func(char *str, ...)
{
int n;
va_list ap; va_start(ap, str);
n = vfprintf(stdout,str,ap);
va_end(ap);
return n;
} int main(void)
{
func("%d%d\n",,);
return ;
}

执行的结果为:

21

果然验证了我的想法,看来这一类函数的用法就是利用va_list记录可变参数位置的特性,将母函数的可变参数列表通过va_list变量转化给v...printf函数的,也就是说跟...printf类的函数是一样的,只不过把...printf类函数的可变参数列表省略,替换成从va_list变量调用而已!

C语言中 v...printf类函数的用法的更多相关文章

  1. C++语言中std::array的神奇用法总结,你需要知道!

    摘要:在这篇文章里,将从各个角度介绍下std::array的用法,希望能带来一些启发. td::array是在C++11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能.也正因此, ...

  2. C++中cout输出字符串和字符串型指针地址值的方法以及C语言中的printf用法比较

    #include <iostream> using namespace std; #include <stdio.h> int main() { char *pstr = &q ...

  3. c语言中external,static关键字用法

    static用法: 在C中,static主要定义全局静态变量.定义局部静态变量.定义静态函数. 1.定义全局静态变量:在全局变量前面加上关键字static,该全局变量变成了全局静态变量.全局静态变量有 ...

  4. C语言中的printf函数的输入输出问题

    这个问题是个很基础,但是我一直不知道的问题,是同学问了之后才知道的,长知识了. 这里要注意的是,printf函数是从右向左计算,从左向右输出. 距离如下: #include <stdio.h&g ...

  5. C语言中mktime函数功能及用法

    今天联系写一个日历的程序,需要算出月份中的第一天是星期几,用到了mktime()这个函数,感觉这个函数挺有用的,分享给大家. 原型:time_t mktime(struct tm *) 其中的tm结构 ...

  6. [原创]c语言中const与指针的用法

    最近一直在准备笔试,补补大一大二欠下的课.复习c语言时碰见这么个题:   1 2 3 4 5 int a=248, b=4; int const c=21; const int *d=&a;  ...

  7. C语言中printf与i++,C++中的cout

    一,printf与i++ 1,C语言中的printf是自右向左输出,. 2,而i++与++i不同的 i++首先取得i的值,下一行时候i = i + 1: ++i,首先i = i + 1,再取得i的值. ...

  8. C语言中malloc()和calloc()c函数用法

    C语言中malloc()和calloc()c函数用法   函数malloc()和calloc()都可以用来动态分配内存空间,但两者稍有区别. malloc()函数有一个参数,即要分配的内存空间的大小: ...

  9. 在不同语言中static的用法

    static (计算机高级语言) 编辑 像在VB,C#,C,C++,Java,PHP中我们可以看到static作为关键字和函数出现,在其他的高级计算机语言如FORTRAN.ALGOL.COBOL.BA ...

随机推荐

  1. Unity UGUI —— 鼠标穿透UI问题(Unity官方的解决方法)

    解决方案 : http://www.cnblogs.com/fly-100/p/4570366.html 这里我们直接在使用Input.GetMouseButtonDown(0)的地方加了一个检测函数 ...

  2. 10 harsh truths that will help you grow

    10 harsh truths that will help you grow帮你成长的10个残酷事实In the game of life, if it often seems like you’r ...

  3. Hadoop基础教程之搭建开发环境及编写Hello World

    整个Hadoop是基于Java开发的,所以要开发Hadoop相应的程序就得用JAVA.在linux下开发JAVA还数eclipse方便. 1.下载 进入官网:http://eclipse.org/do ...

  4. JavaScript DOM编程基础精华03(动态设置,层的操作,性能问题)

    代码是否需要放置到onload中  //如果js代码需要操作页面上的元素,则将该代码放到onload里面.         //因为当页面加载完毕之后页面上才会有相关的元素 //如果js代码中没有操作 ...

  5. NSPoint

    #import <Foundation/Foundation.h>   int main(int argc, const char * argv[]) {    @autoreleasep ...

  6. Java API —— DateFormat类

    1.DateFormat类概述         DateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间. 是抽象类,所以使用其子类SimpleDateForm ...

  7. 使用Maven创建一个Spring MVC Web 项目

    使用Maven创建java web 项目(Spring MVC)用到如下工具: 1.Maven 3.2 2.IntelliJ IDEA 13 3.JDK 1.7 4.Spring 4.1.1 rele ...

  8. (贪心5.2.1)UVA 10026 Shoemaker's Problem(利用数据有序化来进行贪心选择)

    /* * UVA_10026.cpp * * Created on: 2013年10月10日 * Author: Administrator */ #include <iostream> ...

  9. Vim的可视模式

    可视模式可以看到选中的字符串, 并对其进行操作 v:进入字符选择模式 V:进入行选择模式 ctrl-v(Window是ctrl-q):进入block选择模式 o:移动光标到选择的另一端 O:移动光标到 ...

  10. nand flash 扇区的管理以及初始化

    (1)首先需要了解NAND FLASH的结构.如图: 以镁光MT29F4G08BxB Nand Flash为例,这款Flash(如上图)以4个扇区(sector)组成1个页(page),64个页(pa ...