printf中va_list的实现

首先声明下面这个va_list的实现,只适用于32位的机器,像单片机这样int 是2Byte的不适合,但是原理是一样的。

点击(此处)折叠或打开

  1. typedef char * va_list;
  2. #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
  3. #define va_start(ap,v) ( ap = (va_list)&+ _INTSIZEOF(v) )
  4. #define va_arg(ap,t) ( *(*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
  5. #define va_end(ap) ( ap = (va_list))

  6. void test_vparameter(int i,...)
  7. {
  8.     int mm;
  9.     va_list argv;
  10.     va_start(argv,i);
  11.     while(i--)
  12.     {
  13.         mm=va_arg(argv,int);
  14.         putc(mm);
  15.     }
  16.     va_end(argv);
  17. }
1. va_list
printf中va_list的实现_第1张图片
   在调用va_start之前参数都己压入栈中,因为其它的都是可变参数,只有fmt是确定的,fmt是最后压入栈中的,并且每个参数在栈中占用的空间是一样的,所以可以由第一个参数fmt依次推算出其它参数的地址。
2. va_start
printf中va_list的实现_第2张图片
   a. (va_list)&t 取第一个参数fmt的地址
   b. (va_list)&t+_INT_SIZEOF(t) 第一个参数的地址加上参数的长度,此时ap指向了第二个参数即ap指向了第一个可变的参数。

3. va_arg
printf中va_list的实现_第3张图片
   a. ap+=__INT_SIZEOF(t)
ap移动指向第二个可变参数
   b. (ap+=__INT_SIZEOF(t))-__INT_SIZEOF(t)
用指针运算,确定第一个可变参数的地址
   c. (t*)((ap+=__INT_SIZEOF(t))-__INT_SIZEOF(t))
进行强制类型转化
   d. (*(t*)((ap+=__INT_SIZEOF(t))-__INT_SIZEOF(t)))
取出第一个可变参数地址中的值
转自http://blog.chinaunix.net/uid-26009923-id-3261696.html

你可能感兴趣的:(var_list)