易截截图软件、单文件、免安装、纯绿色、仅160KB

对C的printf函数的可变长参数实现的分析

转自【http://tech.ddvip.com/2008-08/121825219252306_3.html】
内容摘要:一直以来都觉得printf似乎是c语言库中功能最强大的函数之一,不仅因为它能格式化输出,更在于它的参数个数没有限制,要几个就给几个,来者不拒。printf这种对参数个数和参数类型的强大适应性,让人产生了对它进行探索的浓厚兴趣。
【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)


相关文档:

c 的 struct,没有结构体名的结构体数据类型

一直对结构体弄的模糊,今天终于有机会澄清了。有个错:不明白没有结构体名的结构体如何像结构体名一样使用。
typedf struct                               st ......

c 语言函数传参的三种方式及二级指针的理解

普通变量是直接传值show(int a,int b)
指针变量传递地址show(int *a,int *b)
引用变量是隐式传地址 1:int x;void show(int &x),实际传递的是x的地址p,但是函数内部使用x时会自动变成*p
                     ......

自己写的C/C++编译器Doctors[软件+文档]

自己写的C/C++编译器Doctors[软件+文档]
http://blog.csdn.net/huyansoft/archive/2009/08/20/4464772.aspx
更新版本1.0.1:该版本解决了之前1.0.0版本中找不到链接库libc.lib的问题,以及IDE下点击Project菜单出现的BUG。下载地址:http://download.csdn.net/source/1597132
Doctors编译器内部实现
For version 1.0.1 ......

C多维数组

 一、多维数组地址的表示方法
  设有整型二维数组a[3][4]如下:
  0 1 2 3
  4 5 6 7
  8 9 10 11
  设数组a的首地址为1000,各下标变量的首地址及其值如图所示。  
在前面曾经介绍过, C语言允许把一个二维数组分解为多个一维数组来处理。因此数组a可分解为三个一维数组,即a[0],a[1], ......
© 2009 ej38.com All Rights Reserved. 关于E健网联系我们 | 站点地图 | 赣ICP备09004571号