printf函数原型:int _cdecl printf(const char*format, …);
首先传递给函数的参数中要有函数用以了解到参数个数的信息,比如printf开始的format字符串,通过%来标识变量,如printf("hello my rank is %d in %d",i,j);printf搜寻第一个参数format指向的字符串"hello my rank is %d in %d"中的%标识,来确定紧跟format之后是两个int变量,再格式化字符串并输出。
细节问题及函数代码说明如下:
1._cdecl是C和C++程序的缺省调用方式,这种方式下参数从右向左入栈(最后压format参数),调用者负责清理堆栈。这种方式适合变参函数的实现,函数调用者知道压入到堆栈多少数据,所以调用完函数后可以相应清理多少数据。
2.如果想实现自己的变参函数,可用到如下的宏定义(这是X86平台的宏定义):
typedef char * va_list;
#define_INTSIZEOF(n)
( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(va_list ap, format) //得到第一个参数的首地址
( ap = (va_list)& format+ _INTSIZEOF(format) )
#define va_arg(va_list ap,type) //将参数转换成需要的类型,并使ap指向下一个参数
( *(type*)((ap += _INTSIZEOF(type)) -_INTSIZEOF(type)) ) //注意括号
#define va_end(va_list ap)
( ap = (va_list)0 )
3.下面以这几个宏来模拟部分实现printf函数(完全可以不用到宏,只是标准库为了定义变参函数的方便)
#include <stdio.h>
#include <stdarg.h>
void myprintf(const char *format, ...)
{
va_list ap;
char ch;
va_start(ap, format);
while(ch = *format++)
{
switch(c)
{
case 'c':
{
char ch1 = va_arg(ap, char);
putchar(ch1);
break;
}
case 's':
{
char *p = va_arg(ap, char *);
fputs(p,stdout);
break;
}
default:
putchar(ch);
}//switch
}//while
va_end(ap);
}//myprintf
4.栈中参数分布以及宏使用后的指针变化说明如下:
![](http://hi.csdn.net/attachment/201203/20/0_1332254515FWEG.gif)
-------------------以上代码图片部分参考自网络白雪-------------------
总结:
对可变参数函数的编写用到上面提到的一些宏就行了,当然也需要是_cdecl的函数调用方式(这是默认的)。通过探究这一主题,也加深了对函数调用方式,函数堆栈参数分布的了解。