该博客把可变参数原理讲述的很清晰
http://blog.csdn.net/hackbuteer1/article/details/7558979
原理:
由于函数调用时需要对参数压栈,而C中采用的是右压栈形式,所以我们可以设定第一个参数必须存在,(因为第一个参数根据右压栈,则第一次参数处于栈顶),这样我们就可以通过该参数地址,获取其他可变参数的地址.
如何实现printf(const char *format,...);如printf("myname:%s,myage:%d\n", name, age);
我们可以获得第一个参数的地址,即字符指针,然后对其指向的字符串进行分析,每当遇到%表示,存在参数,然后va_arg获取该参数输出即可;当是其他字符时,原样输出.
#include<stdio.h>
#include<string.h>
#include<stdarg.h>
//typedef char* va_list;
for allignment
//#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
ap pointer the first variable argument
//#define va_start(ap, v) ( ap = (va_list)&v + _INTSIZEOF(v) )
get the value of ap pointing, and update the ap,pointing next variable argument
//#define va_arg(ap, type) ( *(type *) ((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )
free the ap
//#define va_end(ap) ( ap = (va_list)0 )
int sum(int count, ...)
{
int i;
int sum = 0;
va_list ap;
va_start(ap, count);
for(i = 0; i < count; i++)
{
sum += va_arg(ap, int);
}
va_end(ap);
return sum;
}
int demo(char *msg, ...)
{
va_list ap;
va_start(ap, msg);
char *para = NULL;
int argno = 0;
while(1)
{
para = va_arg(ap, char *);
if(strcmp(para, "\0") == 0)
break;
printf("Parameter #%d is : %s\n", argno, para);
argno++;
}
va_end(ap);
return 0;
}
// "int" Converted into a variety of plastic hex string
void myitoa(int value, char *str, int radix)
{
char *my_str = str;
int mod;
do{
mod = value % radix;
value = value / radix;
//for the hex
if(mod > 9)
*my_str++ = mod - 10 + 'A';
//for the binary,oct,decimal
else
*my_str++ = mod + '0';
}while(value != 0);
*my_str = '\0';
//get the right place
for(my_str--; my_str - str > 0; str++, my_str--)
{
char temp;
temp = *my_str;
*my_str = *str;
*str = temp;
}
}
int myprintf(const char *format, ...)
{
va_list ap;
va_start(ap, format);
char c;
char str[20];
while((c = *format))
{
switch(c)
{
case '%':
{
format++;
char ch = *format;
switch(ch)
{
case 'd':
{
int num_d = va_arg(ap,int);
//printf("## %d##", num_d);
myitoa(num_d, str, 10);
// printf("## %s##", str);
fputs(str, stdout);
break;
}
case 'x':
{
int num_x = va_arg(ap, int);
myitoa(num_x, str, 16);
fputs(str, stdout);
break;
}
case 'c':
{
char num_c = va_arg(ap, int); //va_arg(ap, char) will be error
fputc(num_c, stdout);
break;
}
case 'f':
{
float num_f = va_arg(ap, double);//va_arg(ap, float) will be error
int num = (int)num_f;
myitoa(num, str, 10);
fputs(str, stdout);
fputc('.', stdout);
num = (num_f - num) * 100000;
myitoa(num, str, 10);
fputs(str, stdout);
break;
}
case 's':
{
char *num_s = va_arg(ap, char *);
fputs(num_s, stdout);
break;
}
default:
{
fputs("\ninvalid character\n", stdout);
break;
}
fflush(stdout);
}
break;
}
default:
{
fputc(c, stdout);
fflush(stdout);
break;
}
}
format++;
}
va_end(ap);
return 1;
}
//int main()
//{
// char str[20];
// int num = 21;
// myitoa(num,str,10);
// printf("%s\n", str);
// num = 7;
// myitoa(num,str,2);
// printf("%s\n", str);
// num = 91;
// myitoa(num,str,8);
// printf("%s\n", str);
// num = 252;
// myitoa(num,str,16);
// printf("%s\n", str);
//}
int main()
{
myprintf("a = %d, b = %x, floatnum = %f, character = %c, string =%s, %a\n", 21,252, 121.123, '#', "jacky lau");
int result = sum(3, 'a', 'a', 'a');
printf("result: %d\n", result);
result = sum(3, 1, 2, 3);
printf("result: %d\n", result);
result = sum(3, 1, 2, 'a');
printf("result: %d\n", result);
result = sum(3, 1, 2, 'a');
printf("result: %d\n", result);
demo("DEMO", "My", "name", "is", "Jacky Lau", "\0");
return 1;
}