Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2121624
  • 博文数量: 288
  • 博客积分: 10594
  • 博客等级: 上将
  • 技术积分: 3469
  • 用 户 组: 普通用户
  • 注册时间: 2006-10-27 19:27
文章分类

全部博文(288)

文章存档

2012年(4)

2011年(30)

2010年(40)

2009年(32)

2008年(71)

2007年(79)

2006年(32)

分类: C/C++

2007-11-19 00:23:40

今天在查Linux C函数库时候,一下子翻到了附录,于是看到了不定参数几个字。感觉挺有意思的,而且以前也看到很多不定参数的函数的原型,当时很是不解,很惊叹在不知道函数参数和个数的情况下还能使用。因为时间问题当时也没去了解,现在是该了解的时候了。
其实我们在写C程序的时候,就不知不觉的用到了不定参数,只是不知道的而已。这个函数就是printf()!
这个函数的原型是:
int printf(const char *format[, argument]...);
这个函数的返回类型是int,当它不输出任何字符时返回0。(printf("");)
在format后面的参数不但不定个数,而且类型也是不定的。
这些参数是one by one 的堆 stack 里的,我觉得这个很关键!
那么printf()函数是如何正确的取出这些写参数的呢?
秘诀就在format,函数根据format里的格式("%d %f...")依次把堆在栈里的参数取出来。而这取出的动作就是用到va_arg, va_end, va_start這三個macro再加上va_list。
不定参数相关的表头文件是stdarg.h,在这个头文件中关于以上三个宏和一个变量的定义如下:
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
typedef char *  va_list;
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap)      ( ap = (va_list)0 )
 
首先解释一下宏定义_INTSIZEOF(n),使用macro是为了跨平台时能保持程序运行正确。若传了一个2bytes的不定参数,但在一个32位的平台如堆栈就会是4个bytes,而不是2个bytes,知道意思就好,可能这个例子不太好,所以参数的取出就要非常小心。使用_INTSIZEOF(n)在于保证指针移动正确。这也是预处理的目的之一。
接着解释后面的三个宏,va_list其实就是char *类型的数据,大家都了解吧。
va_start(ap,v);ap的类型就是va_list,v是第一个参数,(va_list)&v得到的是第一个参数的地址,而va_start(ap,v)的到的ap指向的是第二个参数的地址,有人说是第一个参数的地址,我认为是不对的,大家可以做个试验就知道了。不定参函数都是直接给出第一个参数的,他在调用的时候是直接通过这个给出的参数调用的,而不是通过参数指针ap调用的,因为它ap开始处指的就是第二个参数。调用宏va_arg(ap,t)后ap有指向了下一个参数,但这个宏返回的ap指向的上一个参数的指针,仔细分析一下括号就知道了。t是类型名称,可以是int,char等。这个里面还用到了强制类型转换。参数结束的条件由程序自己设定,通常以某个特定的参数表示参数列表结束,用作循环的结束条件。最后va_edn(ap),将ap归零。
下面有两个示例,可以试一试。
#include 
#include 
/*void fun(char *s,...)
{
 va_list  ap;
 int   t;
 va_start(ap,s);
 printf("%s",s);
 while ( (t = va_arg(ap, int)) )
  printf("%d",t);
 va_end(ap);
}
void main()
{
 int a = 1, b = 2, c = 3;
 fun("test:",a,b,c,NULL);
 printf("\n");
}
 
--------------------------------------------------------------------
 
#include 
#include 
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /* Initialize variable arguments. */
printf("marker is : %d\n", *marker);
while( i != -1 )
{
 printf("The sequence of i is: %d\n",i);
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
printf("%d,%d\n", sum, count);//打印总和,输入的数字个数
return( sum ? (sum / count) : 0 );
}
void main()
{
 int avge;
 avge = average(3,4,5,6,-1);
 printf("The average is : %d\n", avge);
}
阅读(2017) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~