#include <stdio.h>
#include <stdarg.h>
void printint(int dec)
{
if(0 == dec)
{
return;
}
printint(dec / 10);
putchar(dec % 10 + '0');
}
void printstr(char *str)
{
while(*str)
{
putchar(*str);
str++;
}
}
void printfloat(float flt)
{
int tempint = (int)flt;
int tempflt = (int)(100000 *(flt - tempint));
if(tempflt % 10 > 5)
{
tempflt = tempflt /10 + 1;
}
else
{
tempflt = tempflt / 10;
}
printint(tempint);
putchar('.');
printint(tempflt);
}
void myprintf(const char *format,...)
{
va_list ap;
va_start(ap,format);
while(*format)
{
if(*format != '%')
{
putchar(*format);
format++;
}
else
{
format++;
switch(*format)
{
case 'c':
{
char val_ch = va_arg(ap,int);
putchar(val_ch);
format++;
break;
}
case 'd':
{
int val_int = va_arg(ap,int);
printint(val_int);
format++;
break;
}
case 's':
{
char * val_str = va_arg(ap,char *);
printstr(val_str);
format++;
break;
}
case 'f':
{
float val_flt = va_arg(ap,double);
printfloat(val_flt);
format++;
break;
}
default :
{
putchar(*format);
format++;
}
}
}
}
va_end(ap);
}
va_start()宏初始化ap以供va_arg()和va_end()随后使用,并且必须在他们前面定义。参数last是可变参数列表之前的最后一个参数的名称,调用函数知道其类型的最后一个参数。因为这个参数的地址可能在va_start()宏中使用,它不应该被声明为寄存器变量,或者作为函数或数组类型。
va_start()宏初始化va_list型的变量ap,ap是存储参数地址的指针。因为得到参数的地址后,再结合参数的类型,就能得到参数的值。
va_arg()宏扩展为具有调用中的下一个参数的类型和值的表达式。 参数ap是由va_start()初始化的va_list ap。 每次调用va_arg()都会修改ap,以便下一次调用返回下一个参数。参数类型是指定的类型名称,以便可以通过向类型中添加*来获取指向具有指定类型的对象的指针的类型。在va_start()宏之后第一次使用va_arg()宏将返回最后一个参数。 连续调用返回其余参数的值。如果没有下一个参数,或者如果类型与实际下一个参数的类型不兼容,则会出现随机错误。如果ap被传递给使用va_arg(ap,type)的函数,则ap的值在该函数返回后是未定义的。
依次使用va_arg宏使得ap返回可变参数的地址,得到这个地址后,结合参数的类型,就可以得到参数的值。