__vfprintf_internal 源码
时间: 2023-11-16 18:04:13 浏览: 226
__vfprintf_internal 是一个内部函数,用于实现 printf 和 fprintf 等函数的底层输出功能。以下是 __vfprintf_internal 函数的源代码:
```c
int __vfprintf_internal(FILE *stream, const char *format, va_list ap, int *writelen)
{
int ret;
unsigned int len;
unsigned char flags = 0;
unsigned char prec = 0;
unsigned char width = 0;
unsigned char type = 0;
unsigned char sign = 0;
unsigned char prefix = 0;
unsigned char base = 0;
unsigned char *p;
int n;
int count = 0;
char buf[BUF_SIZE];
char *s;
unsigned long long value;
const char *digits;
const char *prefix_str;
char pad_char = ' ';
char prefix_char = '\0';
/* ... */
/* 根据格式字符串逐个处理输出 */
for (p = (unsigned char *)format; *p; p++) {
/* 处理格式控制指示符 */
if (*p == '%') {
flags = 0;
prec = 0;
width = 0;
type = 0;
sign = 0;
prefix = 0;
base = 10;
prefix_str = "";
pad_char = ' ';
prefix_char = '\0';
/* 处理标志位 */
p++;
while (*p == '-' || *p == '+' || *p == ' ' || *p == '#' || *p == '0') {
switch (*p) {
case '-':
flags |= LEFT_ADJUSTMENT;
break;
case '+':
flags |= PLUS_SIGN;
break;
case ' ':
flags |= SPACE;
break;
case '#':
flags |= ALTERNATE_FORM;
break;
case '0':
flags |= ZERO_PAD;
break;
}
p++;
}
/* 处理字段宽度 */
if (*p >= '0' && *p <= '9') {
while (*p >= '0' && *p <= '9') {
width = width * 10 + (*p - '0');
p++;
}
} else if (*p == '*') {
width = va_arg(ap, int);
if (width < 0) {
width = -width;
flags |= LEFT_ADJUSTMENT;
}
p++;
}
/* 处理精度 */
if (*p == '.') {
p++;
prec = 0;
if (*p >= '0' && *p <= '9') {
while (*p >= '0' && *p <= '9') {
prec = prec * 10 + (*p - '0');
p++;
}
} else if (*p == '*') {
prec = va_arg(ap, int);
p++;
}
flags |= PRECISION;
}
/* 处理长度修饰符 */
switch (*p) {
case 'h':
if (*(p + 1) == 'h') {
p++;
flags |= CHAR_SHORT;
} else {
flags |= SHORT;
}
p++;
break;
case 'l':
if (*(p + 1) == 'l') {
p++;
flags |= LLONG;
} else {
flags |= LONG;
}
p++;
break;
case 'j':
flags |= INTMAX_T;
p++;
break;
case 'z':
flags |= SIZE_T;
p++;
break;
case 't':
flags |= PTRDIFF_T;
p++;
break;
case 'L':
flags |= LONG_DOUBLE;
p++;
break;
default:
break;
}
/* 处理转换类型 */
type = *p;
switch (type) {
case 'd':
case 'i':
if (flags & LLONG) {
value = va_arg(ap, long long);
} else if (flags & LONG) {
value = va_arg(ap, long);
} else if (flags & SHORT) {
value = (short)va_arg(ap, int);
} else if (flags & CHAR_SHORT) {
value = (signed char)va_arg(ap, int);
} else {
value = va_arg(ap, int);
}
if (value < 0) {
sign = '-';
value = -value;
} else if (flags & PLUS_SIGN) {
sign = '+';
} else if (flags & SPACE) {
sign = ' ';
}
base = 10;
digits = "0123456789";
break;
case 'o':
if (flags & LLONG) {
value = va_arg(ap, unsigned long long);
} else if (flags & LONG) {
value = va_arg(ap, unsigned long);
} else if (flags & SHORT) {
value = (unsigned short)va_arg(ap, unsigned int);
} else if (flags & CHAR_SHORT) {
value = (unsigned char)va_arg(ap, unsigned int);
} else {
value = va_arg(ap, unsigned int);
}
base = 8;
digits = "01234567";
if (flags & ALTERNATE_FORM && value != 0) {
prefix_str = "0";
prefix_char = '0';
prefix = 1;
}
break;
case 'u':
if (flags & LLONG) {
value = va_arg(ap, unsigned long long);
} else if (flags & LONG) {
value = va_arg(ap, unsigned long);
} else if (flags & SHORT) {
value = (unsigned short)va_arg(ap, unsigned int);
} else if (flags & CHAR_SHORT) {
value = (unsigned char)va_arg(ap, unsigned int);
} else {
value = va_arg(ap, unsigned int);
}
base = 10;
digits = "0123456789";
break;
case 'x':
case 'X':
if (flags & LLONG) {
value = va_arg(ap, unsigned long long);
} else if (flags & LONG) {
value = va_arg(ap, unsigned long);
} else if (flags & SHORT) {
value = (unsigned short)va_arg(ap, unsigned int);
} else if (flags & CHAR_SHORT) {
value = (unsigned char)va_arg(ap, unsigned int);
} else {
value = va_arg(ap, unsigned int);
}
base = 16;
digits = (type == 'X') ? "0123456789ABCDEF" : "0123456789abcdef";
if (flags & ALTERNATE_FORM && value != 0) {
prefix_str = (type == 'X') ? "0X" : "0x";
prefix_char = (type == 'X') ? 'X' : 'x';
prefix = 2;
}
break;
case 'p':
value = (uintptr_t)va_arg(ap, void *);
base = 16;
digits = "0123456789abcdef";
prefix_str = "0x";
prefix_char = 'x';
prefix = 2;
break;
case 'c':
n = va_arg(ap, int);
buf[0] = n;
s = buf;
len = 1;
break;
case 's':
s = va_arg(ap, char *);
if (s == NULL) {
s = "(null)";
}
len = strlen(s);
if (flags & PRECISION && len > prec) {
len = prec;
}
break;
case '%':
buf[0] = '%';
s = buf;
len = 1;
break;
default:
buf[0] = '%';
buf[1] = type;
s = buf;
len = 2;
break;
}
/* 计算输出长度 */
if (type == 's') {
count += len;
} else {
if (value == 0 && (flags & PRECISION) && prec == 0) {
len = 0;
} else {
len = calc_digits(value, base);
}
if (sign || prefix) {
len++;
}
count += (len < width) ? width : len;
}
/* 输出前导空格或零 */
if (!(flags & LEFT_ADJUSTMENT)) {
if (flags & ZERO_PAD) {
pad_char = '0';
}
while (count < width) {
fputc(pad_char, stream);
count++;
}
}
/* 输出符号或前缀 */
if (sign) {
fputc(sign, stream);
count++;
} else if (prefix) {
fputs(prefix_str, stream);
count += prefix;
}
/* 输出数字或字符串 */
if (type == 's') {
fwrite(s, len, 1, stream);
} else {
output_number(value, base, digits, prefix_char, stream, len);
}
/* 输出后缀空格 */
if (flags & LEFT_ADJUSTMENT) {
while (count < width) {
fputc(' ', stream);
count++;
}
}
} else {
/* 处理普通字符 */
fputc(*p, stream);
count++;
}
}
/* 返回输出字符数 */
if (writelen) {
*writelen = count;
}
ret = ferror(stream) ? EOF : count;
return ret;
}
```
该函数首先解析格式字符串,然后根据格式字符串逐个处理输出。具体而言,它会根据格式字符串中的格式控制指示符,处理标志位、字段宽度、精度、长度修饰符和转换类型等信息,并据此输出相应的内容。输出时会考虑前导空格、符号或前缀、数字或字符串以及后缀空格等因素。最后,该函数会返回输出字符数,并将其写入指针 `writelen` 所指向的变量中。
阅读全文