VARARGS,STDARGS,可变参数列表摘要

来源:互联网 发布:人工智能企业 新三板 编辑:程序博客网 时间:2024/05/21 10:38

一、是否可以只使用一组整数参数来复制任意类型的数值?(理论上,只要函数参数个数支持,这仅是对内存解释的不同)

 

关于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;

}

 

 

 

 

 

 

 

 

 

 

原创粉丝点击