转自http://book.51cto.com/art/200902/109024.htm
http://hi.baidu.com/zzzkkk666/blog/item/683ac15472d29e5cd10906dd.html
5.4.1. 变长参数的使用
5.4 函数的变长参数
文件的格式化输入输出函数都支持变长参数。定义时,变长参数列表通过省略号"…"表示,因此,具有变长参数列表的函数定义格式为:
type 函数名(参数1, 参数2, 参数n, ...);
其中type为函数的返回值类型,参数1~参数n为定长参数,"..."代表变长参数,注意"..."必须定义在参数的最右端。如下例:
int printf(const char *format, ...); int mysum(...);
|
5.4.1. 变长参数的使用
Unix的变长参数通过va_list对象实现,定义在文件"stdarg.h"中,变长参数的应用模板如代码5-15所示:
代码5-15 变长参数代码模板
#include <stdarg.h> function (parmN, ...) va_list pvar; …………………………… va_start (pvar, parmN); while() { …………………… f = va_arg (pvar, type); …………………… } va_end (pvar);
|
1. va_list pvar
申明va_list数据类型变量pvar,该变量访问变长参数列表中的参数。
2. va_start(pvar, parmN)
宏va_start初始化变长参数列表。pvar是va_list型变量,在步骤1中定义,记载列表中的参数信息。parmN是省略号"..."前的一个参数名,va_start根据此参数,判断参数列表的起始位置,如:
例1. 函数:function(parmN, …)
答:va_start(pvar, parmN);
例2. 函数:int mysum(int i, int j, …)
答:va_start(pvar, j);
3. va_arg(pvar, type)
获取变长参数列表中参数的值。pvar是步骤1中定义的va_list型变量,type为参数值的类型,也是宏va_arg返回数值的类型,如:
va_arg(pvar, int); /* 将参数列表中的当前参数值转化为int型返回 */ va_arg(pvar, float); /* 将参数列表中的当前参数值转化为float型返回*/
|
宏va_arg执行完毕后自动更改对象pvar,将其指向下一个参数。
4. va_end(pvar)
关闭本次对变长参数列表的访问。
实例
设计函数mysum,计算输入参数的和并返回结果。源程序如代码5-16所示:
代码5-16 变长参数函数实例(节自/code/chapter5/mysum.c)
#include <stdarg.h> int mysum(int i, ...) /* 参数i表明变长参数的个数 */ { int r=0, j=0; va_list pvar; va_start(pvar, i); for (j=0; j<i; j++) { r += va_arg(pvar, int); } va_end(pvar); return(r); } void main() { printf("sum(1,4)=%d\n", mysum(1, 4)); printf("sum(2,4,8)=%d\n", mysum(2, 4, 8)); }
|
编译与运行代码5-16:
# make mysum cc -O -o mysum mysum.c # ./mysum sum(1,4)=4 sum=(2,4,8)=12
|
5.4.2 变长参数的传递
5.4.2 变长参数的传递
上一节讲述了如何创建具有变长参数的函数和如何读取变长参数,其操作都在函数内完成,本节将讲述把变长参数列表整体作为参数传递给其他函数的方法。
变长参数传递的函数族如下:
#include <stdarg.h> int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap);
|
这些函数完全等价于格式化输出函数,只是在形式上采用固定参数代替变长参数,这样描述的函数更加紧凑,这些函数常应用于变长参数函数内部的功能实现。
实例
设计函数"int PrintLog(FILE* stream, const char* pformat, ...)",它按照字符串format的内容,控制后继参数的数量和格式,并在文件流stream中输出。源程序如代码5-17所示:
代码5-17 传递变长参数实例(节自/code/chapter5/print1.c)
#include <stdarg.h> #include <stdio.h> int PrintLog(FILE* pfile, const char * pformat, ...) { va_list _va_list; char szBuf[1024]; if (pformat == NULL || pfile == NULL) return -1; /* 判断指针是否正确*/ va_start(_va_list, pformat); /* 初始化变长参数列表 */ vsprintf(szBuf, pformat, _va_list); /* 传递变长参数 */ va_end(_va_list); /* 结束使用变长参数列表 */ fputs(szBuf, pfile); /* 输出到文件流 */ return 0; } void main() { PrintLog(stderr, "[%s][%s][%d][%c]\n", "This", "Is", 5, 'a'); PrintLog(stderr, "Error[%p][%.2f][%X]\n", NULL, 3.123, 100); }
|
编译与运行代码5-17:
# make print1 cc -O print1.c -o print1 # ./print1 [This][Is][5][a] Error[00000000][3.12][64]
|
【实践经验】对于指针类型的参数,最好在函数入口处判断其是否为空,以免空指针引用错误。如代码5-17中黑体部分。
C语言中可变参数的宏
2007年12月24日 星期一 21:09
今天来说说宏。什么?宏也能可变参数?是的,你没有听错,带参数的宏和函数一样,同样支持可变参数。下面通过一个小程序加以说明。
#include
#include
#define OUTSCREEN(msg, ...) printf(msg,__VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");
return 0;
}
这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。
#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");
return 0;
}
假如我们将上面的代码稍作一下修改,变成下面的样子。
#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!");
return 0;
}
注意我仅仅是将main函数里的OUTSCREEN做了修改,这时可变参数的个数为0了。但是编译的时候gcc却报错:
In function `main':
error: parse error before ')' token
什么原因导致出错呢?把宏展开一下看看,原来是","惹得祸。那么这种参数个数可以为0的宏要怎么写呢?C99的规范没有定义这个,gcc对此做了扩展。重新定义OUTSCREEN宏如下:
#define OUTSCREEN(msg, ...) printf(msg, ##__VA_ARGS__)
当可变参数的个数为0时,这里的##起到把前面多余的","去掉,实际上变成了printf(msg),这样编译就能通过了。
另外,__VA_ARGS__这个宏实在不利于记忆,gcc对此做了扩展,另一种可接受的定义方法为:
#define OUTSCREEN(msg, args...) printf(msg, ##args)
贴上代码,权当练习之用
#include <stdio.h>
//#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)
//#define OUTSCREEN(msg, ...) printf(msg, ##__VA_ARGS__)
#define OUTSCREEN(msg, args...) printf(msg, ##args)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World=====%s\n");
//OUTSCREEN("Hello World=====%s", "__This is an example\n");
// OUTSCREEN("Hello World=====%s", "__This is an example\n", "77777777777");
return 0;
}
分享到:
相关推荐
一、前言 今天在看Thinking in C++这本书时,书中的一个例子引起了我的注意,具体是...C/C++中规定了函数参数的压栈顺序是从右至左,对于含有不定参数的printf函数,其原型是printf(const char* format,…);其中f
变长参数的函数,即参数个数可变、参数类型不定的函数。设计一个参数个数可变、参数类型不定的函数是可能的,最常见的例子是printf函数、scanf函数和高级语言的Format函数。最近的一个项目中就遇到这么一个相关的...
不定参数在C语言中的应用实例:不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多。除了格式化输出之外,我实在没看到多少应用。主要原因是这种技术比较麻烦,副作用也比较多,而...
不定参数在C语言中的应用实例:不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多。除了格式化输出之外,我实在没看到多少应用。主要原因是这种技术比较麻烦,副作用也比较多,而...
27.cpp //vector(不定长数组) 28.cpp //map(映射) 29.cpp //结构体swap 30.cpp //结构体sort xiao3 31.cpp //计算两日期间隔 32.cpp //加密4个数 33.cpp //计算日期星期 34.cpp //queue(队列) 35.cpp //stack...
由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载。对这种情况,提出了指针参数来解决问题。 如printf()函数,其原型为:int printf( ...
首先,所谓可变参数指的是函数的参数个数可变,参数类型不定的函数。为了编写能处理不同数量实参的函数,C++提供了两种主要的方法:如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型;如果...
php的基本语法和c/c++,java的差不多,只是php在定义变量时没有要显示声明变量类型,php对变量的...所以在函数中可以根据不同情况返回不同类型的值,以及可以向函数传入不定数量的参数,这一点像c/c++,java是做不到的
C++ Primer中文版(第5版)[203M]分3个压缩包 本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数...
C++ Primer中文版(第5版)[203M]分3个压缩包 本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数...
不指定范围产生随机数用到函数rand(),函数原型为int rand(),无参数。此时会产生一个介于0~RAND_MAX间的整数。RAND_MAX的大小可以查看,在include文件夹(linux在usr目录、windows在安装目录)的stdlib.h可以看到...
这段程序是一个C语言的小技巧,其展示了如何把一个参数为结构体的函数转成一个可变参数的函数。
7.4.4 在构造函数中使用初始化列表 320 7.5 类的私有成员 320 7.5.1 访问私有类成员 323 7.5.2 类的友元函数 324 7.5.3 默认复制构造函数 326 7.6 this指针 328 7.7 类的const对象 331 7.7.1 类的...
涉及到自定义类的构造函数、重载构造函数、函数默认值、析构函数、复制构造函数、重载运算符(赋值函数、加法函数)、虚函数、常值函数、...不定参数函数、友函数、友类、类型引用、终态函数、终态类、模板变量等内容...
由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦;即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,有些人采用指针参数来解决问题。
C++11版本特性(参数数量不定的模板)将参数进行分解,类似于递归的情况,每一个每一个·进进行打印,要函数出口...就是一个所谓的pack(包)nullptr用
由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦;即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,有些人采用指针参数来解决问题.下面就c语言中处理不定参数数目的问题进行讨论
代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...
如果搞不定自己电脑上的编程软件,我们也会提供在网页中编写、运行C语言程序的方法。 课程大纲 01 程序设计与C语言 课时 1 计算机和编程语言 2 C语言 3 第一个程序 02 计算 课时 1 变量 2 数据类型 3 表达式 4 ...
答:在单片机开发中,主要是汇编和C,没有用C++的。 3. 搞单片机开发,一定要会C吗? 答:汇编语言是一种用文字助记符来表示机器指令的符号语言,是最接近机器码的一种语言。其主要优点是占用资源少、程序...