浅析printf中的变参传递

这篇文章主要探讨一种printf的实现,这个是一个实时地记录,错误在所难免,还请谅解。

原型

首先我们来看看printf的实现原型:

typedef struct
{
    int32_t dest;            // 定义输出终端
    void (*func)(char);      // 定义输出函数
    char *loc;
} PRINTK_INFO;

int printf (const char *fmt, ...)
{
    va_list ap;        // 变参宏定义, char *ap
    int32_t rvalue;    // 返回值
    PRINTK_INFO info;
    /* 初始化info变量 */
    info.dest = DEST_CONSOLE;
    info.func = &out_char;
    /*
     * Initialize the pointer to the variable length argument list.
     */
    va_start(ap, fmt);    //(void)(ap = (char *)&fmt)
    rvalue = printk(&info, fmt, ap);
    /*
     * Cleanup the variable length argument list.
     */
    va_end(ap);
    return rvalue;
}

我们来看看va_list, va_start, va_end, va_arg的定义:

#ifndef _MSL_VA_LIST_TYPE
    #define _MSL_VA_LIST_TYPE char *
#endif
#ifndef _MSL_VA_LIST_DEFINED
    typedef _MSL_VA_LIST_TYPE va_list;
    #define _MSL_VA_LIST_DEFINED
#endif
#define __va_start(parm) (__std(va_list))(&parm) /*- mm 981014 -*/
#define va_start(ap, parm) (void)(ap = (va_list)&parm)    /*- US 011402 -*/
    
#define va_arg(ap, type) \
    (__builtin_vargtype(type) == 1 \
    ? /* Float or Long Aligned Types */\
    (*(type *) (((((unsigned int)((ap)))>>1)&1) == 1 ? ((ap)-=(sizeof(type) +2)) : ((ap)-=sizeof(type)))) \
    : /* Everything else */\
     (*(type *) ((ap) -=((sizeof(type) <= 2) ? 2:sizeof(type))))\
    )
    
#define va_end(ap) ((void) 0)                                              

这里看起来va_list就是一个指针而已。再来看看printk里面是怎么读取这个参数的:

int32_t ival;
int32_t vlen;
char vstr[33];
char *vstrp;
ival = (int32_t)va_arg(ap, int32_t);
vlen = printk_mknumstr(vstr,&ival,TRUE,10);
vstrp = &vstr[vlen];

我们来展开va_arg这个宏:

(int32_t)va_arg(ap, int32_t);
/* type convert */
(long)va_arg(ap, long);
/* micro convert */
(long) (*long *)(((((unsigned int)((ap))) >> 1)&1) == 1 ? ((ap)-=(sizeof(long) + 2)) : ((ap)-=sizeof(long))))

这里实际就是按照类型的大小直接移动相应的大小,然后进行强制类型转换,当然这个都是要和编译器相对应的,因为参数具体怎么传递还是和编译器相关的。


本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

发表新评论