【C】——可变参数
写代码之前要先介绍一下可变参数的备用知识;
C函数要在程序中用到以下这些宏:
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
- va_list:用来保存宏va_start、va_arg和va_end所需信息的一种类型。为了访问变长参数列表中的参数,必须声明va_list类型的一个对象。定义: typedef char * va_list;
- va_start:访问变长参数列表中的参数之前使用的宏,它初始化用va_list声明的对象,初始化结果供宏va_arg和va_end使用;
- va_arg: 展开成一个表达式的宏,该表达式具有变长参数列表中下一个参数的值和类型。每次调用va_arg都会修改。用va_list声明的对象,从而使该对象指向参数列表中的下一个参数;
- va_end:该宏使程序能够从变长参数列表用宏va_start引用的函数中正常返回。
va在这里是variable-argument(可变参数)的意思.
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件.下面我们写一个简单的可变参数的函数,改函数至少有一个整数参数,第二个参数也是整数,是可选的.函数只是打印这两个参数的值.
了解了这些知识之后就可以写下我们的第一个可变参数的函数了;
void myprintf(const char *format, ...)
{
va_list argp; //定义保存函数参数的结构
int argno = ; //记录参数个数
char *para; //存放取出的字符串参数 va_start(argp, format); //argp指向传入的第一个可选参数 while()
{
para = va_arg( argp, char *); //取出当前的参数,类型为char *
if(strcmp( para, "\0") == )
break;
printf("parameter #%d is %s\n",argno,para);
argno++;
}
printf("format is %s\n",format);
va_end(argp); //将argp置为NULL
}
需要注意的是
- 函数定义的时候第二个参数必须是三个.;
- 必须用va_start宏初始化argp;
- 用完之后必须用va_end宏将argp置空;
此函数的调用方法是: myprintf("printf","this","is","a","text","!","\0");//取\0为结束符 我们需要用一个字符'\0'来确定是否是最后一个字符;
此函数是从第二个参数来输出的;那么第一个参数是用来干什么的呢?貌似第一个函数除了初始化的时候用到了,其他的时候都没有用到。我们再写一个函数来看看第一个参数的用处:
void myprintf_two(int format, ...)
{
va_list argp;
int argno = ;
int fora = format;
char *para; va_start(argp,format);
while(fora--)
{
para = va_arg(argp,char *);
printf("parameter #%d %s\n",argno,para);
argno++;
}
printf("format is %d\n",format);
va_end(argp); }
哦,原来第一个参数可以是int类型的;这下了解了第一个函数的用处了吧@!
在用可变参数函数的时候需要注意一点,就是在获取float类型的时候一定要用double接收;来看个函数:
double add(int n, ...)
{
va_list argp;
va_start(argp,n);
double sum = .;
while(n--)
sum += va_arg(argp,double);
va_end(argp);
return sum;
}
如果把va_arg(argp,double)改成:va_arg(argp,float)就会报错了:

就这么多吧,附上完整的代码:
#include <stdio.h>
#include <string.h>
#include <stdarg.h> void myprintf(const char *format, ...)
{
va_list argp; //定义保存函数参数的结构
int argno = ; //记录参数个数
char *para; //存放取出的字符串参数 va_start(argp, format); //argp指向传入的第一个可选参数 while()
{
para = va_arg( argp, char *); //取出当前的参数,类型为char *
if(strcmp( para, "\0") == )
break;
printf("parameter #%d is %s\n",argno,para);
argno++;
}
printf("format is %s\n",format);
va_end(argp); //将argp置为NULL
} void myprintf_two(int format, ...)
{
va_list argp;
int argno = ;
int fora = format;
char *para; va_start(argp,format);
while(fora--)
{
para = va_arg(argp,char *);
printf("parameter #%d %s\n",argno,para);
argno++;
}
printf("format is %d\n",format);
va_end(argp); } double add(int n, ...)
{
va_list argp;
va_start(argp,n);
double sum = .;
while(n--)
sum += va_arg(argp,double);
va_end(argp);
return sum;
} int main(void)
{
myprintf("printf","this","is","a","text","!","\0"); //取\0为结束符
myprintf_two(,"this","is","a","text");
printf("sum(10,20) = %g\n",add(,10.0,20.0));
return ;
}
利用 vsnprintf 配合 va_list 操作传递进来的参数:
#include <stdio.h>
#include <stdarg.h>
int mon_log(char* format, ...)
{
char str_tmp[];
int i=;
va_list vArgList; //定义一个va_list型的变量,这个变量是指向参数的指针.
va_start (vArgList, format); //用va_start宏初始化变量,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数
i=_vsnprintf(str_tmp, , format, vArgList); //注意,不要漏掉前面的_
va_end(vArgList); //用va_end宏结束可变参数的获取
return i; //返回参数的字符个数中间有逗号间隔
}
//调用上面的函数
void main()
{
int i=mon_log("%s,%d,%d,%d","asd",,,);
printf("%d\n",i);
}
【C】——可变参数的更多相关文章
- C可变参数的函数
我们实现一个简单的printf函数(可变参数) #include <stdio.h> #include <stdarg.h> void myprintf(const char ...
- c#编程基础之函数可变参数
可变参数:int sum (params int[] values)int sum (string name,params int[] values) 注意:params参数必须是形参表中的最后一个参 ...
- C语言的可变参数在Linux(Ubuntu)与Windows下注意点
基本上C语言的可变参数原理在不同平台和不同编译器下基本类似(通过函数入栈,从右向左,从高位到低位地址),不过部分实现会有所不同:在使用中需要注意的是: va_list 为char 类型指针,部分调用如 ...
- 可变参数列表与printf()函数的实现
问题 当我们刚开始学习C语言的时候,就接触到printf()函数,可是当时"道行"不深或许不够细心留意,又或者我们理所当然地认为库函数规定这样就是这样,没有发现这个函数与普通的函数 ...
- C#与Java对比学习:数据类型、集合类、栈与队列、迭达、可变参数、枚举
数据类型: C#:String与StringBuilder Java:String与StringBuffer 第一个不习惯是string的第一个字母必须大写了. 第二个不习惯是int得写成Intege ...
- params可变参数
class Program { // params可变参数 //将实参列表中跟可变参数数组类型一致的元素都当做数组的元素去处理. //params可变参数必须是形参列表中的最后一个元素. static ...
- java高新技术-可变参数与OverLoad相关面试题分析
可变参数 可变参数的特点: 只能出现在参数列表的最后: ...位于变量类型和变量名之间,前后有无空格都可以: 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法中以数组的形式访问可变参数 ...
- C和指针 第七章 可变参数
可变参数列表是通过stdarg.h内的宏来实现的: 类型 va_list 三个宏: va_start va_arg va_end 我们可以声明一个va_list变量,与这三个宏配合使用. 可变参数必须 ...
- java可变参数
Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理.注意:可变参数必须位于最后一项.当可变参数个数多余一个时,必将有一个不是最后一项,所以只支持 ...
- 可变参数宏__VA_ARGS__和...
__VA_ARGS__ 是一个可变参数的宏(gcc支持).实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点).这样预定义宏_ _VA_ARGS_ _就可以被用在替换部分中,替换省略号所 ...
随机推荐
- GitHub创始人:我如何放弃30万美元年薪创业
GitHub创始人:我如何放弃30万美元年薪创业 本文摘自GitHub创始人Tom Preston Werner个人博客. 时间还在2007年,我一个人独坐旧金山的Zeke 体育酒吧内.其实我并不经常 ...
- 设置Myeclipse中的代码格式化、注释模板及保存时自动格式化
1:设置注释的模板: 下载此模板: codetemplates.xml 搜索Dangzhang,将其改为你自己的姓名,保存 打开eclipse/myeclipse选择 window-->Pre ...
- unity, 立即生效动画:Animation.sample()
在调用了动画播放之后,动画并不会立即应用(骨骼Transform并不会立即改变),最快也要等到本帧lateUpdate才能生效. 如果有特殊需求,希望在调用了动画播放之后立即生效,则可以紧接着调一句A ...
- python 元类(metaclass)
元类参见老师的博客 http://www.cnblogs.com/linhaifeng/articles/8029564.html
- 在 Windows 7 中安装 .NET Framework 时遇到错误:无法建立到信任根颁发机构的证书链
当全新安装 Windows 7 SP1 后,在未安装任何补丁,也未进行联网的状态下,安装 .NET Framework 4.6 或更高的版本时,应该会遇到错误提示:无法建立到信任根颁发机构的证书链. ...
- 解决 emoji表情存入数据库为' ??? '
今天把mysql切换为mariaDB,这是题外话 主要是emoji标签存入数据库会发现出现三个???的问题 页面上也显示不出来,解决办法只要把内容从数据库里拿出来的时候解码即可 for (Feedba ...
- Atitti 固化数据库表结构方案
Atitti 固化数据库表结构方案 1. 固化数据库表结的重要意义1 2. 如何固化表结构1 2.1. 向上抽象一层,以动词有目标,以名词为存储对象.1 2.2. 数据类型datatype字段:这个用 ...
- 【Unity】4.1 创建组件
分类:Unity.C#.VS2015 创建日期:2016-04-05 一.简介 组件(Component)在Unity游戏开发工作中非常重要,可以说是实现一切功能所必需的. 1.游戏对象(Game O ...
- 基于 vue 全家桶的 spa 项目脚手架
项目简介 Github: https://github.com/hanan198501/vue-spa-template 我们基于 vue-cli 脚手架生成项目模板做了一些改造,加入了 vue-ro ...
- Word实用教程——五分钟教你如何在任意页开始添加页码
最近在写一篇论文,但是在排版上遇到一点小问题,就是要加入页码,而且页码是从目录的下一页开始计数,于是我就在网上找如何在任意页添加页码.后来辗转终于搞定,真心觉得这一个小功能让微软做的如此的麻烦,真是活 ...