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

时间:2022-05-10 03:40:28

        在前面的博文中, 我彻谈了从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;
}
       不多说。