从va_list、va_start、va_arg、va_end想到了vsprintf的源码

来源:互联网 发布:mac移动硬盘无法分区 编辑:程序博客网 时间:2024/05/19 02:45

        在前面的博文中, 我彻谈了从va_list、va_start、va_arg、va_end的用法, 但是, 当我看到某个程序后, 非常纳闷, 于是迫不及待得想知道vsprintf的实现。

        在我的第一印象中, vsprintf貌似和vs有关, 也就是和微软有关, 所以懒得去管微软那些东东, 其实, vsprintf和微软没有毛关系, linux也有这个东东,而v是variable的缩写。 看来, 是我误解vsprintf了。


        我们先看看这段代码(我之前写的):

#include <iostream>#include <string>#include <fstream>#include <cstdarg>using namespace std;void log(const char *format, ...){va_list args;va_start(args, format);char buf[4096] = {0};vsprintf(buf, format, args);va_end(args);ofstream outfile("log.txt", ios::app);outfile << buf << endl;}int main(){log("%s%d, %s%d", "practice", 1, "practice", 2);return 0;}
        看到vsprintf那一行, 只用了args, 没有用av_arg啊,  这就必然要求vsprintf中利用args和av_arg, 而且会遍历变参, 并利用format(依赖于其中的格式化字符串进而对变参进行解析), 这是必然的。

        我都不知道该说点什么了, 还是迫不及待地看看vsprintf的源码吧(最后一个参数的类型是va_list):

int vsprintf(char *buf, const char *fmt, va_list args){    char *str, *s;    int base;    int flags = 0;    int fildwidth = -1;    int precision = -1;    int qualifier;    unsigned long num;    for(str = buf; *fmt != '\0'; fmt++) {        if(*fmt == '\t') {            int k = 8;            while(k--)                *str++ = ' ';            fmt++;        }        if(*fmt != '%') {            *str++ = *fmt;            continue;        }handle_flags:        fmt++;        switch (*fmt) {            case '#':                    flags |= PREFIX;                    goto handle_flags;            }    /* handle_fldwidth: */        /* don't need this now */    /* handle_precision: */        /* don't need this now */    /* handle_lenmodifier: */        /* don't need this now */    /* handle_qualifier: */        qualifier = -1;        if(*fmt == 'l' || *fmt == 'L' || *fmt == 'h') {            qualifier = *fmt;            fmt++;        }    /* handle_convtype: */        base = 10;        switch(*fmt) {            case 'c':                /* processing alignment */                *str = (unsigned char)va_arg(args, int);                /* processing alignment */                continue;            case 's':                s = va_arg(args, char *);                str = strcpy(str, s);         /* is it safe? */                str--;                continue;            case 'd':                break;            case 'o':                    base = 8;                    break;            case 'x':                 flags |= SMALL;            case 'X':                base = 16;                break;            default:                *str++ = '%';                if(*fmt)                    *str++ = *fmt;                else                    fmt--;                continue;        }        if (qualifier == 'l')            num = va_arg(args, unsigned long);        else if (qualifier == 'h')                    num = (unsigned short)va_arg(args, int);        else {            num = va_arg(args, int);        }        str = num2str(str, num, base, fildwidth, precision, flags);    }    *str = '\0';    return str - buf;}
        再来看看我们最常用的printf的实现吧, 很俗套了:

int printf(const char *fmt, ...){    char buf[1024];    va_list args;    int cnt;    va_start(args, fmt);    cnt = vsprintf(buf, fmt, args);    va_end(args);        putstr(buf);    return cnt;}    
       不多说。



0 0
原创粉丝点击