变参函数:
#include <stdarg.h>
va_list p;
va_start(p,fmt );
va_arg( p, int);
va_end( p );
以上四个到底是由什么函数或者宏定义构成的?下面来揭晓
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) (*(t *)(ap = ap + _INTSIZEOF(t), ap - _INTSIZEOF(t)))
#define va_end(ap) ( ap = (va_list)0 )
四个宏定义解释如下:
vc6.0中的stdarg.h
typedef char * va_list;
1、#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
//当sizeof(n)=1/2/4时,_INTSIZEOF(n)等于4
2、#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
/*
va_start(p, format ) ( p = (char *)&format + _INTSIZEOF(format) )
( p = (char *)&format + _INTSIZEOF(char *) )
( p = (char *)&format + 4 )
*/
3、#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
/*
#define va_arg(ap,t) (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))
移动指针到下一个可变参数 将当前可变参数的值取出
(ap-偏移)然后取值
#define va_arg(ap,t) (*(t *)(ap = ap + _INTSIZEOF(t), ap - _INTSIZEOF(t)))
将当前可变参数的值取出 移动指针到上一个可变参数
(ap+偏移)然后取值
*/
4、#define va_end(ap) ( ap = (va_list)0 )
/*
#define va_end(ap) ( ap = (char *)0 )
*/
代码如下:
#include <stdio.h>
//#include <stdarg.h>
//以下代码为变参函数的内部定义,将其直接插入程序,作用和头文件声明效果相同。
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
//以下三句等价。先移动指针,后取值和先取值,后移动指针
//#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
//#define va_arg(ap,t) (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))
#define va_arg(ap,t) (*(t *)(ap = ap + _INTSIZEOF(t), ap - _INTSIZEOF(t)))
#define va_end(ap) ( ap = (va_list)0 )
struct person{
char *name;
int age;
char score;
int id;
};
/*
*int printf(const char *format, ...);
*依据:x86平台,函数调用时参数传递是使用堆栈来实现的
*目的:将所有传入的参数全部打印出来
*/
int push_test(const char *format, ...)
{
//char *p = (char *)&format;
int i;
struct person per;
char c;
double d;
va_list p;
printf("arg1 : %s\n",format);
//==============
//p = p + sizeof(char *);
va_start(p, format );
/*指针对连续空间操作时: 1) 取值 2)移动指针*/
//i = *((int *)p);
//p = p + sizeof(int);
i = va_arg(p,int);
printf("arg2 : %d\n",i);
//==============
/*指针对连续空间操作时: 1) 取值 2)移动指针*/
//per = *((struct person *)p);
//p = p + sizeof(struct person);
per = va_arg(p,struct person);
printf("arg3: .name = %s, .age = %d, .socre=%c .id=%d\n",\
per.name, per.age, per.score, per.id);
//==============
/*指针对连续空间操作时: 1) 取值 2)移动指针*/
//c = *((char *)p);
//p = p + ((sizeof(char) + 3) & ~3);
c = va_arg(p,int);
printf("arg4: %c\n",c);
//==============
/*指针对连续空间操作时: 1) 取值 2)移动指针*/
//d = *((double *)p);
//p = p + sizeof(double);
d = va_arg(p,double);
/*避免"野指针"*/
//p = (char *)0;
va_end( p );
printf("arg5: %f\n",d);
return 0;
}
int main(int argc,char **argv)
{
struct person per={"www.100ask.org",10,'A',123};
printf("sizeof(char )=%d\n",sizeof(char ));
printf("sizeof(int )=%d\n",sizeof(int ));
printf("sizeof(char *)=%d\n",sizeof(char *));
printf("sizeof(char **)=%d\n",sizeof(char **));
printf("sizeof(struct person)=%d\n",sizeof(struct person));
//push_test("abcd");
//push_test("abcd",123);
//push_test("abcd",123,per);
//push_test("abcd",123,per,'c');
push_test("abcd",123,per,'c',2.79); //此处的“abcd”不懂???
return 0;
}
关于可变参数:
有时,希望函数带有可变数量的参数,而不是预定义数量的参数。
C 语言为这种情况提供了一个解决方案,它允许您定义一个函数,能根据具体的需求接受可变数量的参数。
下面的实例演示了这种函数的定义。
int func(int, ... )
{
.
.
.
}
int main()
{
func(2, 2, 3);
func(3, 2, 3, 4);
}
请注意,函数 func() 最后一个参数写成省略号,即三个点号(...),省略号之前的那个参数是 int,代表了要传递的可变参数的总数。为了使用这个功能,您需要使用 stdarg.h 头文件,该文件提供了实现可变参数功能的函数和宏。具体步骤如下:
- 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
- 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。
- 使用 int 参数和 va_start 宏来初始化 va_list 变量为一个参数列表。宏 va_start 是在 stdarg.h 头文件中定义的。
- 使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项。
- 使用宏 va_end 来清理赋予 va_list 变量的内存。
现在让我们按照上面的步骤,来编写一个带有可变数量参数的函数,并返回它们的平均值:
#include <stdio.h>
#include <stdarg.h>
double average(int num,...)
{
va_list valist;
double sum = 0.0;
int i;
/* 为 num 个参数初始化 valist */
va_start(valist, num);
/* 访问所有赋给 valist 的参数 */
for (i = 0; i < num; i++)
{
sum += va_arg(valist, int);
}
/* 清理为 valist 保留的内存 */
va_end(valist);
return sum/num;
}
int main()
{
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}
当上面的代码被编译和执行时,它会产生下列结果。应该指出的是,函数 average() 被调用两次,每次第一个参数都是表示被传的可变参数的总数。省略号被用来传递可变数量的参数。
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000