#include <varargs.h>
void error(va_list)va_dcl
{
va_list ap;
char *format;
va_start(ap);
format=va_arg(ap,char *);
fprintf(stderr,"error: ");
//某些实现方式暂时未知的工作
va_end(ap);
fprintf(stderr,"\n");
exit(1);
}
//error函数的最终版本
#include <varargs.h>
#include <stdio.h>
void error(va_alist)va_dcl
{
va_list ap;
va_start(ap);
char *format;
format=va_arg(ap,char *);
fprintf(stderr,"error: ");
vfprintf(stderr,format,ap);
va_end(ap);
fprintf(stderr,"\n");
exit(1);
}
//利用vprintf来实现printf函数的一种可行的方法,注意不要忘记保存vprintf的结果,我们需要把这个结果返回给printf函数的调用者
#include <varargs.h>
printf(va_list)va_dcl
{
va_list ap;
char *format;
int n;
va_start(ap);
format=va_arg(ap,char *);
n=vprintf(format,ap);
va_end(ap);
return n;
}
//实现varargs.h的一个典型实现的一组宏
typedef char *va_list;
#define va_dcl int va_alist;
#define va_start(list) list=(char *)&va_alist;//va_list甚至不是一个宏,只是一个int型的参数,而且va_list就只是一个简单的字符指针,但是在底层的c语言实现中要求函数参数在内存中连续存贮,这样我们只需知道当前参数的地址,就能依次访问参数列表中的其他参数,宏va_start把它的参数设置为va_alist的地址(为避免lint程序警告,这里做了类型转化,而宏va_end则什么也没做)
#define va_end(list)
#define va_arg(list,mode) ((mode*)(list+=sizeof(mode)))[-1]
//最复杂的是宏va_arg,它必须返回一个由va_list所指向的恰当类型的数值,同时递增va_list,使它指向参数列表中的下一个参数,(即递增的大小等于与va_arg宏所返回的数值具有相同类型的对象的长度)。应为类型转化的结果不能作为赋值运算的目标,所以只能先赋值再做类型转化,而不能先类型转化再赋值,所以va_arg宏首先使用sizeof来确定需要递增的大小,然后直接把它加到va_list上,这样得到的指针再被转化为要求的类型,应为该指针现在指向的位置过了一个类型单位的大小,所以我们使用了下标-1来存取正确的返回参数
//这里有一个陷阱需要避免,va_arg的的第二个参数不能被指定为char,short或float类型,应为char和short类型的参数会被转化为int类型,而float类型的参数会自动被自动转化为double类型,应为之前的函数参数没有声明,但是当第二个参数作为指针时,指针并不会自动转化,只有short,char和float型的数值才会自动转化
使用varargh.h来实现可变参数列表以及varargh.h实现
最新推荐文章于 2020-09-07 15:17:07 发布