参数在c语言中,如何在C语言中定义参数数目可变的函数

如何在C语言中定义参数数目可变的函数

提前声明:由于我对C的理解还不够深刻,所以这个东西里面可能会有些常识性的错误,欢迎各位不吝指出。希望这个东西对大家有所帮助。

昨天晚上偶然看到一篇文章,讲到了C语言可变数目参数的函数。其实很早之前我就注意到中的几个函数的参数个数是可变的,但一直不知道怎么实现。看了那篇文章,稍微有了点思路。

首先,文章介绍了几个宏——va_start, va_end, va_arg。我查了一下C99,其7.15节介绍的就是Variable Arguments(我比较奇怪的是, C99在这一节中的介绍顺序, va_list->va_arg->va_copy->va_end->va_start, 呵呵). 简单说一下这几个va_开头的东西的含义吧.

(1) va_list: typedef char* va_list

va_start: 声明为 void va_start ( va_list ap, parmN );

顾名思义, va_start要在所有其它的va_开头的宏前面最先使用(除了用va_list定义变量外), va_start的作用就是初始化ap, 因为后面的va_copy, va_arg, va_end都要使用到ap. C99说的很明白, 由va_start和va_end构成一个scope, 所以在一对va_start和va_end之间不能再次使用va_start. parmN 就是"..."之前的最后一个参数. 例如, printf函数是这样定义的: printf(const char *format, ...); 那么在printf函数中的va_start使用之后, parmN 的值就等于*format.

(2) va_arg: 声明为 type va_arg (va_list ap, type);

va_arg的作用就是返回参数列表ap中的下一个具有type类型的参数, 每次调用va_arg都会修改ap的值, 所以你才能"连续不断"的获取下一个type类型的参数. ap就是前面使用va_start初始化的ap.

(3) va_copy: 声明为 void va_copy (va_list dest, va_list src);

其作用是将src中的内容复制到dest中, dest成为src的一个副本.

(4) va_end: 声明为 void va_end (va_list ap);

va_end与va_start构成了一个scope, va_end之后ap就无效了.

其实C99的这些规定已经足够我们使用了. 让人欣慰的是, GCC提供了更加便捷有效的方式来处理这些va_开头的宏. 在GCC的中定义了三个宏: VA_OPEN, VA_FIXEDARG, VA_CLOSE. 在注释中这样说:

/*

...

VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end. Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls corresponding to the list of fixed arguments.  Then use va_arg normally to get the variable arguments, or pass your va_list object around.  You do not declare the va_list yourself; VA_OPEN does it for you.

...

You can declare variables either before or after the VA_OPEN, VA_FIXEDARG sequence.  Also, VA_OPEN and VA_CLOSE are the beginning and end of a block.  They must appear at the same nesting level, and any variables declared after VA_OPEN go out of scope at VA_CLOSE.  Unfortunately, with a K+R compiler, that includes the argument list.  You can have multiple instances of VA_OPEN/VA_CLOSE pairs in a single function in case you need to traverse the

argument list more than once.

...

*/

也就是说, 如果我们使用VA_OPEN和VA_CLOSE那么连定义va_list的变量也省了. 我们可以看一下VA_OPEN, VA_CLOSE, VA_FIXEDARG的定义:

#define VA_OPEN(AP, VAR)     { va_list AP; va_start(AP); { struct Qdmy

#define VA_CLOSE(AP)         } va_end(AP); }

#define VA_FIXEDARG(AP, TYPE, NAME)    TYPE NAME = va_arg(AP, TYPE)

我们可以根据需要来使用这些宏.

下面我们就来写一个例子, 编译环境DevCpp 4.9.9.2

21c92f7342edc52acb5684b0b88bdcec.png程序代码:#include

#include

#include

#include

#define va_list char*

// 这个其实是GCC的中的示例程序, 作用就是printf

int vary_args PARAMS ((const char *format, ...));

// 这个是我简单写的一个函数, 作用是求最大值

int max_v PARAMS ((int nValue, ...));

int main(int argc, char *argv[])

{

char str[] = "Hello, world. \n %s";

char str2[] = "World, hello.\n";

int nResult = vary_args(str, str2);

printf("nResult = %d\n", nResult);

int nMaxV = max_v(6, 5, 3, 4);

printf("nMaxV = %d\n", nMaxV);

system("pause");

return 0;

}

int vary_args VPARAMS ((const char *format, ...))

{

int result = 0;

VA_OPEN (ap, format);

VA_FIXEDARG(ap, const char *, format);

result = vfprintf(stdout, format, ap);

/* 关于vfprintf和stdout这里先不作说明, 有兴趣的可以查阅相关资料 */

VA_CLOSE(ap);

return result;

}

int max_v PARAMS ((int nValue, ...))

{

int result = 0, nTemp = 0;

VA_OPEN(ap, nValue);

result = nValue;

while (strcmp(ap, ""))

{

//VA_FIXEDARG(ap, int, nTemp);

nTemp = va_arg(ap, int);

if (nTemp > result)

result = nTemp;

}

VA_CLOSE(ap);

return result;

}

[[italic] 本帖最后由 zbqf109 于 2007-12-31 01:45 编辑 [/italic]]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值