printf()原理及可变参函数的实现

Jan 20, 2010

可变参数主要由stdarg.h中定义的以下四个宏实现:(va_list是stdarg.h中定义的数据类型)

  1. void va_start(va_list , ):在example(type b...)中使用用va_start(va_list a, type b)后, va_list型的a被初始化,使之指向第一个可选参数。
    注:ANSI C规定,可变参数前没有固定参数的函数是非法的。例如:int ERROR(...)是不被允许的
  2. type va_arg(va_list ,type):该函数返回当前a指向的type型的参数,并使a指向下一个参数
  3. void va_end(valist):valist设为null
  4. void va_copy(valist,valist):复制va_list型变量

下面,自己动手写一个可变参函数:

/*(int max(int num, int first...)接收num个int参数,返回他们中的最大值*/
/*max(3, a, b, c );调用*/
#include 
#include 
using namespace std;

int max (int num, int first...);
int main()
{
    int a, b, c;
    cin >> a >> b >> c;
    cout << "the biggest among a,b,c is " << max(3, a, b, c) << endl;
    return 0;
}
int max(int num, int first...)
{
    valist str;
    int bigger = first;
    vastart(str, first);
    for(int i = 1; i < num; i++)
    {
        int val = vaarg(str, int);
        bigger = (val > bigger)? val : bigger;
    }
    vaend(str);
    return bigger;
}

printf()源码分析

改函数的定义如下:int printf (const char *cntrlstring, …)。cntrlstring是控制字符串

函数流程如下:

vastart(ap, cntrlstring);
while(cntrlstring[n]){
   if (cntrlstring[n] == "%"){
       n++;                                 
       switch(cntrl_string[n]){
       case 'c':
           .......
       case 'd':
           .......
       .......
       }
   }
}

以case 'c'为例:

case 'c':
putchar(vaarg(ap, unsigned char));
cnt
printed_chars++;
break;

下面是自己写的一个printf()的简易实现:

/*只实现字符输出*/
#include 
#include 

void printbyl(const char *str,...);
int main()
{
     char str[100] = "my name is %c%c%c";
     char a = 'b', b = 'y', c = 'l';
     printbyl(str, a, b, c);
     return 0;
}
void printbyl(const char *str,...)
{
     valist ap;
     vastart(ap, str);
     int n = 0;
     while(str[n])
     {
         if(str[n] == '%')
         {
             n++;
             switch(str[n])
             {
                 case 'c':
                 putchar(vaarg(ap, int));
                 break;
                 default:
                 putchar('%');
                 putchar(str[n]);
             }
             n++;
         }
         else
         {
             putchar(str[n]);
             n++;
         }
    }
    va_end(ap);
}

原理: 通过查看汇编代码发现:可变参函数通过是宏的调用,把可变参数复制到函数栈侦中,通过访问局部变量的形式访问可变参数的。

Get In Touch With Us ...