WEB开发网
开发学院软件开发VC 从printf谈可变参数函数的实现 阅读

从printf谈可变参数函数的实现

 2008-08-09 19:25:55 来源:WEB开发网   
核心提示:1. 使用情形 int a =10;double b = 20.0;char *str = "Hello world";printf("begin print");printf("a=%d, b=%.3f, str=%s", a, b, str);...从pr

1. 使用情形

int a =10;
double b = 20.0;
char *str = "Hello world";
printf("begin print
");
printf("a=%d, b=%.3f, str=%s
", a, b, str);
...
  从printf的使用情况来看,我们不难发现一个规律,就是无论其可变的参数有多少个,printf的第一个参数总是一个字符串。而正是这第一个参数,使得它可以确认后面还有有多少个参数尾随。而尾随的每个参数占用的栈空间大小又是通过第一个格式字符串确定的。然而printf到底是怎样取第一个参数后面的参数值的呢,请看如下代码

2. printf 函数的实现

//acenv.h
typedef char *va_list;
#define _AUPBND    (sizeof (acpi_native_int) - 1)
#define _ADNBND    (sizeof (acpi_native_int) - 1)
            
#define _bnd(X, bnd)  (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T)  (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap)   (void) 0
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
//start.c
static char sprint_buf[1024];
int printf(char *fmt, ...)
{
  va_list args;
  int n;
  va_start(args, fmt);
  n = vsprintf(sprint_buf, fmt, args);
  va_end(args);
  write(stdout, sprint_buf, n);
  return n;
}
//unistd.h
static inline long write(int fd, const char *buf, off_t count)
{
  return sys_write(fd, buf, count);
}
3. 分析

从上面的代码来看,printf似乎并不复杂,它通过一个宏va_start把所有的可变参数放到了由args指向的一块内存中,然后再调用vsprintf. 真正的参数个数以及格式的确定是在vsprintf搞定的了。由于vsprintf的代码比较复杂,也不是我们这里要讨论的重点,所以下面就不再列出了。我们这里要讨论的重点是va_start(ap, A)宏的实现,它对定位从参数A后面的参数有重大的制导意义。现在把 #define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) 的含义解释一下如下:

1 2 3  下一页

Tags:printf 可变 参数

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接