一、是否可以只使用一组整数参数来复制任意类型的数值?(理论上,只要函数参数个数支持,这仅是对内存解释的不同)
关于Printf的实现 第一个参数必须是一个字符串。//??
1.在知道第一个参数类型的情况下,就可以对其进行存取。
2.一旦第n个参数被存取,第n+1个参数就可以在仅知道类型的情况下进行存取。
3.按这种方式存取一个参数所需的时间不应太多。
大多数c语言都是通过一组VARARGS来实现上述目的。
带有可变参数列表的函数,必须在函数定义的首部使用va_alist和va_dcl 宏。
#include<vararg.h>
void error (va_alist) va_dcl
varargs.h的一个典型实现
typedef char *va_list;
#define va_dcl int va_alist;
#define va_start(list) l list=(char *)&va_alist
#define va_end(list)
#define va_arg(list,mode) ((mode*)(list+=sizeof(mode)))[-1] //可以看到这里限制后面的参数是顺序存取。
所以上面error被扩展为
typedef char* va_list
void error(va_alist) int va_alist /*表面看来,仅仅是一个整型参数*/
这个例子的假定:底层的c语言实现要求函数参数在内存中连续存储,这样我们只需知道当前参数的地址,就能依次访问参数列表中的其他参数。
因此,vararg.h的这个实现中,va_list就只是一个简单的字符指针。宏va_start把它的参数设置为va_alist的地址,并进行了类型转换,而宏
va_end 则什么也不做。
回到??的地方,我们看到这组宏定义,并没有标识给定的参数数目,所以使用varargs系列宏的每个程序,都有责任通过确立某种约定或惯例来标志参数列表的结束。而printf函数使用格式字符串作为第一个参数,通过它来识别参数数目与类型。
例子:使用vprintf函数来实现printf,前者直接使用va_list类型参数。
#include<varargs.h>
int printf(va_alist) va_dcl
{
va_list ap;
char* format;
int n;
va_start(ap);//ap指向va_alist参数列表
format=va_arg(ap,char*);//获取char* 类型参数,同时更新ap指向下一个参数起始位置。
n=vprintf(format,ap);
va_end(ap); //不同实现,可能要求释放内存。
return n;
}
二、ANSI的varargs.h
ANSI提供了一组新的标准来实现可变参数功能。
具有可变参数列表的函数,他们的第一个参数的类型在每次调用时实际上都是不变的。类似printf这样的函数,可以通过检查它的第一个参数,来确定它的第2个参数的类型。但是,从参数列表中我们不能确定第一个参数的类型。
使用stdarg.h的函数至少有一个固定类型的参数,后面可以跟一组未知数目,位置类型的参数。
stdarg.h文件中没有va_arg和va_dcl宏,使用stdarg.h的函数直接声明其固定参数,把最后一个固定定参数作为va_sart宏的参数,来访问可变参数。
列子:
#include <stdarg,h.
int printf ( char * format,..)
{
va_list ap;
int n;
va_start(ap,format);//多了一个format,ap 指向后续可变参数
n=vprintf(format,ap);
va_end(ap);
return n;
}