使用stdarg.h实现可变长度参数

现在先用一个使用过程讲解一下:

◎用法: 
func( Type para1, Type para2, Type para3, … ) 

/****** Step 1 ******/ 
va_list ap; 
va_start( ap, para3 ); //一定要“…”之前的那个参数 ,而且这个参数不能使引用类型,因为引用类型不能根据其地址获取后面参数的地址

/****** Step 2 ******/ 
//此时ap指向第一个可变参数 
//调用va_arg取得里面的值

Type xx = va_arg( ap, Type );

//Type一定要相同,如: 
//char *p = va_arg( ap, char *); 
//int i = va_arg( ap, int );

//如果有多个参数继续调用va_arg

/****** Step 3 ******/ 
va_end(ap); //For robust! 

然后写个小程序,大家看看就明白了stdarg.h的用法了

#include <iostream>

#include <stdarg.h>

const int N=5;

using namespace std;

void Stdarg(int a1,…)

{

va_list argp;

int i;

int  ary[N];

va_start(argp,a1);

ary[0]=a1;

for(i=1;i< N;i++)

ary[i]=va_arg(argp,int);

va_end(argp);

for(i=0;i< N;i++)

cout<<ary[i]<<endl;

}

void main()

{

Stdarg(5,12,64,34,23);

}

最后我们来分析一下stdarg.h这个头文件(呵呵,本人也是看的不太懂)

typedef char * va_list;

#define va_start _crt_va_start 
#define va_arg _crt_va_arg 
#define va_end _crt_va_end

#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) 
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) – _INTSIZEOF(t)) ) 
#define _crt_va_end(ap) ( ap = (va_list)0 ) 
va_list argptr; 
C语言的函数是从右向左压入堆栈的,调用va_start后, 
按定义的宏运算,_ADDRESSOF得到v所在的地址,然后这个 
地址加上v的大小,则使ap指向第一个可变参数如图:

栈底 高地址 
| ……. 
| 函数返回地址 
| ……. 
| 函数最后一个参数 
| …. 
| 函数第一个可变参数 <–va_start后ap指向 
| 函数最后一个固定参数 
| 函数第一个固定参数 
栈顶 低地址

然后,用va_arg()取得类型t的可变参数值, 先是让ap指向下一个参数: 
ap += _INTSIZEOF(t),然后在减去_INTSIZEOF(t),使得表达式结果为 
ap之前的值,即当前需要得到的参数的地址,强制转换成指向此参数的 
类型的指针,然后用*取值

最后,用va_end(ap),给ap初始化,保持健壮性。

example:(chenguiming)

#include <stdio.h> 
#include <ctype.h> 
#include<stdlib.h> 
#include <stdarg.h>

int average( int first, … ) //变参数函数,C++里也有 

int count=0,i=first,sum=0; 
va_list maker; //va_list 类型数据可以保存函数的所有参数,做为一个列表一样保存 
va_start(maker,first); //设置列表的起始位置 
while(i!=-1) 

sum+=i; 
count++; 
i=va_arg(maker,int);//返回maker列表的当前值,并指向列表的下一个位置 

return sum/count;

}

void main(void) 

printf( "Average is: %d\n", average( 2, 3, 4,4, -1 ) ); 
}

Linux下的stdarg.h

#ifndef _STDARG_H 
#define _STDARG_H

typedef char *va_list; /* 定义va_list 是一个字符指针类型*/

/* Amount of space required in an argument list for an arg of type TYPE. 
TYPE may alternatively be an expression whose type is used. */ 
/* 下面给出了类型为TYPE 的arg 参数列表所要求的空间容量。 
TYPE 也可以是使用该类型的一个表达式 */

// 下面这句定义了取整后的TYPE 类型的字节长度值。是int 长度(4)的倍数。 
#define __va_rounded_size(TYPE) \ 
(((sizeof (TYPE) + sizeof (int) – 1) / sizeof (int)) * sizeof (int))

// 下面这个函数(用宏实现)使AP 指向传给函数的可变参数表的第一个参数。 
// 在第一次调用va_arg 或va_end 之前,必须首先调用该函数。 
// 17 行上的__builtin_saveregs()是在gcc 的库程序libgcc2.c 中定义的,用于保存寄存器。 
// 它的说明可参见gcc 手册章节“Target Description Macros”中的 
// “Implementing the Varargs Macros”小节。 
#ifndef __sparc__ 
#define va_start(AP, LASTARG) \ 
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) 
#else 
#define va_start(AP, LASTARG) \ 
(__builtin_saveregs (), \ 
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) 
#endif

// 下面该宏用于被调用函数完成一次正常返回。va_end 可以修改AP 使其在重新调用 
// va_start 之前不能被使用。va_end 必须在va_arg 读完所有的参数后再被调用。 
void va_end (va_list); /* Defined in gnulib *//* 在gnulib 中定义 */ 
#define va_end(AP)

// 下面该宏用于扩展表达式使其与下一个被传递参数具有相同的类型和值。 
// 对于缺省值,va_arg 可以用字符、无符号字符和浮点类型。 
// 在第一次使用va_arg 时,它返回表中的第一个参数,后续的每次调用都将返回表中的 
// 下一个参数。这是通过先访问AP,然后把它增加以指向下一项来实现的。 
// va_arg 使用TYPE 来完成访问和定位下一项,每调用一次va_arg,它就修改AP 以指示 
// 表中的下一参数。 
#define va_arg(AP, TYPE) \ 
(AP += __va
_rounded_size (TYPE), \ 
*((TYPE *) (AP – __va_rounded_size (TYPE))))

#endif /* _STDARG_H */

时间: 2024-07-31 05:19:17

使用stdarg.h实现可变长度参数的相关文章

编写一个可变参数的C函数——头文件stdarg.h中宏va_start ,va_arg和va_end的应用

我们在C语言编程中会遇到一些参数个数可变的函数,例如printf()这个函数,它的定义是这样的:int printf( const char* format, ...);它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:printf("%d",i);printf("%s",s);printf("the number is %d ,string is:%s", i, s);究竟如何写可变参数的

stdarg.h——用于函数接受可变参数

stdarg.h是C语言中C标准函数库的头文件,stdarg是由standard(标准) arguments(参数)简化而来,主要目的为让函数能够接收可变参数. 1.可变参数函数 声明可变参数函数 可变参数函数的参数数量是可变动的,它使用省略号来忽略之后的参数.例如printf函数一般.代表性的声明为: int check(int a, double b, ...); 可变参数函数最少要有一个命名的参数,所以 char *wrong(...); 在C中是不被允许的(在C++中,这样的声明是合理的

#include&lt;stdarg.h&gt; 可变参数使用

今天上计算方法这课时觉得无聊至极,于是拿出C++编程之道来看了看..无意之中看到了#include<stdarg.h> va_list,va_start,va_end等东西,不知是怎么用的,于是很想解决.. 课后速回到宿舍,打开电脑一查才    知道原来是:定义成一个可变参数列表的指针: 于是写下了下面的一小程序加以运用(开发环境为vs2005) #include<stdio.h>#include<stdarg.h>int N=5;void Stdarg(int a1,

第 16 章 C 预处理器和 C 库(可变参数:stdarg.h)

1 /*------------------------------------------------- 2 varargs.c -- use variable number of arguments 3 -------------------------------------------------*/ 4 5 #include <stdio.h> 6 #include <stdarg.h> 7 8 double sum(int, ...); 9 10 int main()

#include &lt;stdarg.h&gt;

名称描述相容  // 作用描述 va_start使va_list指向起始的参数 va_arg检索参数C89 va_end释放va_list va_copy拷贝va_list的内容 实例解析: #include <stdio.h> #include <stdarg.h> void printargs(int arg1, ...) /* 输出所有int类型的参数,直到-1结束 */  //参数列表中, 后面的元素类型不一定,va_arg()函数的返回类型决定的 { va_list ap

头文件&lt;stdarg.h&gt;

头文件<stdarg.h>声明了一种类型并且定义了三个宏,这样就可以提前访问一个参数表,调用函数在被编译时并不知道这个参数表中参数的数目和类型.其目的是是为了让函数能够接受可变参数. 1.类型:va_list 它是一个保存宏va_start.va_arg和va_end所需要的信息的类型.如果要访问不同的参数,那么调用的函数要声明一个va_list类型的数据对象(假设该数据对象名为ap).对象ap可能作为参数传递给另一个函数.如果那个函数对参数ap调用宏va_arg,那么ap在调用函数中的值是不

#include&lt;stdarg.h&gt;

stdarg.h是C语言中C标准函数库的头文件,stdarg是由standard(标准) arguments(参数)简化而来,主要目的为让函数能够接收可变参数.C++的cstdarg头文件中也提供这样的功能:虽然与C的头文件是兼容的,但是也有冲突存在. VA_LIST 是在C语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h>,用于获取不确定个数的参数 va_start,函数名称,读取可变参数的过程其实就是在堆栈中,使用指针,遍历堆栈段中的参数列表,从低地址到高地址一

C 标准库 - &lt;stdarg.h&gt;

C 标准库 - <stdarg.h> 简介 stdarg.h 头文件定义了一个变量类型 va_list 和三个宏,这三个宏可用于在参数个数未知(即参数个数可变)时获取函数中的参数. 可变参数的函数通在参数列表的末尾是使用省略号(,...)定义的. 库变量 下面是头文件 stdarg.h 中定义的变量类型: 序号 变量 & 描述 1 va_list 这是一个适用于 va_start().va_arg() 和 va_end() 这三个宏存储信息的类型. 库宏 下面是头文件 stdarg.h

stdarg.h

standrad parameter 该头文件包含了一个变量类型和3个宏 变量类型 va_list #ifndef _VA_LIST_DEFINED #ifdef _M_ALPHA typedef struct { char *a0; /* pointer to first homed integer argument */ int offset; /* byte offset of next parameter */ } va_list; #else typedef char * va_lis