C语言中 v...printf类函数的用法
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类函数的用法的更多相关文章
- C++语言中std::array的神奇用法总结,你需要知道!
摘要:在这篇文章里,将从各个角度介绍下std::array的用法,希望能带来一些启发. td::array是在C++11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能.也正因此, ...
- C++中cout输出字符串和字符串型指针地址值的方法以及C语言中的printf用法比较
#include <iostream> using namespace std; #include <stdio.h> int main() { char *pstr = &q ...
- c语言中external,static关键字用法
static用法: 在C中,static主要定义全局静态变量.定义局部静态变量.定义静态函数. 1.定义全局静态变量:在全局变量前面加上关键字static,该全局变量变成了全局静态变量.全局静态变量有 ...
- C语言中的printf函数的输入输出问题
这个问题是个很基础,但是我一直不知道的问题,是同学问了之后才知道的,长知识了. 这里要注意的是,printf函数是从右向左计算,从左向右输出. 距离如下: #include <stdio.h&g ...
- C语言中mktime函数功能及用法
今天联系写一个日历的程序,需要算出月份中的第一天是星期几,用到了mktime()这个函数,感觉这个函数挺有用的,分享给大家. 原型:time_t mktime(struct tm *) 其中的tm结构 ...
- [原创]c语言中const与指针的用法
最近一直在准备笔试,补补大一大二欠下的课.复习c语言时碰见这么个题: 1 2 3 4 5 int a=248, b=4; int const c=21; const int *d=&a; ...
- C语言中printf与i++,C++中的cout
一,printf与i++ 1,C语言中的printf是自右向左输出,. 2,而i++与++i不同的 i++首先取得i的值,下一行时候i = i + 1: ++i,首先i = i + 1,再取得i的值. ...
- C语言中malloc()和calloc()c函数用法
C语言中malloc()和calloc()c函数用法 函数malloc()和calloc()都可以用来动态分配内存空间,但两者稍有区别. malloc()函数有一个参数,即要分配的内存空间的大小: ...
- 在不同语言中static的用法
static (计算机高级语言) 编辑 像在VB,C#,C,C++,Java,PHP中我们可以看到static作为关键字和函数出现,在其他的高级计算机语言如FORTRAN.ALGOL.COBOL.BA ...
随机推荐
- 【mongoDB中级篇②】索引与expain
索引的操作 数据库百分之八十的工作基本上都是查询,而索引能帮我们更快的查询到想要的数据.但是其降低了数据的写入速度,所以要权衡常用的查询字段,不必在太多字段上建立索引. 在mongoDB中默认是用bt ...
- posix 线程(一):线程模型、pthread 系列函数 和 简单多线程服务器端程序
posix 线程(一):线程模型.pthread 系列函数 和 简单多线程服务器端程序 一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属 ...
- Linux和Linux之间共享目录
1.Linux 服务器端NFS服务器的配置 以root身份登陆Linux服务器,编辑/etc目录下的共享目录配置文件exports,指定共享目录及权限等. 执行如下命令编辑文件/etc/exports ...
- KDE/QT与GNOME/GTK比较
转自:http://linux.chinaunix.net/bbs/thread-1125240-1-1.html 虽然在商业方面存在竞争,GNOME与KDE两大阵营的开发者关系并没有变得更糟,相反他 ...
- SqlServer几个注意点
1.修改系统参数时,必须是单用户情况下才能更改成功!在Properties->Options中修改. 2.数据库字段值默认是不区分大小写的,修改方法如下: 2.1.右键数据库,选择Propert ...
- HDU-4661 Message Passing 树形DP,排列组合
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4661 题意:有n个人呈树状结构,每个人知道一个独特的消息.每次可以让一个人将他所知的所有消息告诉和他相 ...
- ZOJ 3349 Special Subsequence 简单DP + 线段树
同 HDU 2836 只不过改成了求最长子串. DP+线段树单点修改+区间查最值. #include <cstdio> #include <cstring> #include ...
- jsp获取struts2查询到的数据
1.在struts2的方法中利用查询语句查询到结果,然后再对结果进行封装,jsp根据封装获取相关信息 struts2的查询和封装方法: private List<FreeMarkerDetail ...
- [转载]深入理解JAVA的接口和抽象类
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
- Android开发之“点9”
“点九”是andriod平台的应用软件开发里的一种特殊的图片形式,文件扩展名为:.9.png智能手机中有自动横屏的功能,同一幅界面会在随着手机(或平板电脑)中的方向传感器的参数不同而改变显示的方向,在 ...