🆕 完成了vsprintf和数字转字符串

This commit is contained in:
fslongjin 2022-01-23 14:43:50 +08:00
parent 1afa20dc55
commit cbbd2e1bf4
2 changed files with 195 additions and 11 deletions

View File

@ -2,6 +2,7 @@
// Created by longjin on 2022/1/22.
//
#include "printk.h"
#include <math.h>
int skip_and_atoi(const char **s)
{
@ -17,7 +18,7 @@ int skip_and_atoi(const char **s)
}
return ans;
}
int vsprintf(char *buf, const char *fmt, va_list args)
static int vsprintf(char *buf, const char *fmt, va_list args)
{
/**
* fmt和args中的内容进行格式化buf中
@ -45,6 +46,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
{
*str = *fmt;
++str;
continue;
}
//开始格式化字符串
@ -164,6 +166,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
}
break;
//显示一个字符串
case 's':
s = va_arg(args, char *);
@ -188,7 +191,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
*str = ' ';
++str;
}
for (int i = 0; i < len; i++)
{
*str = *s;
@ -196,17 +199,183 @@ int vsprintf(char *buf, const char *fmt, va_list args)
++str;
}
while (len<field_width--)
while (len < field_width--)
{
*str = ' ';
++str;
}
break;
//以八进制显示字符串
case 'o':
if (qualifier == 'l')
write_num(str, va_arg(args, long long), 8, field_width, precision, flags);
else
write_num(str, va_arg(args, int), 8, field_width, precision, flags);
break;
//打印指针指向的地址
case 'p':
if (field_width == 0)
{
field_width = 2 * sizeof(void *);
flags |= PAD_ZERO;
}
write_num(str, (unsigned long)va_arg(args, void *), 16, field_width, precision, flags);
break;
//打印十六进制
case 'x':
flags |= SMALL;
case 'X':
if (qualifier == 'l')
write_num(str, va_arg(args, long long), 16, field_width, precision, flags);
else
write_num(str, va_arg(args, int), 16, field_width, precision, flags);
break;
//打印十进制有符号整数
case 'i':
case 'd':
case 'ld':
flags |= SIGN;
if (qualifier == 'l')
write_num(str, va_arg(args, long long), 10, field_width, precision, flags);
else
write_num(str, va_arg(args, int), 10, field_width, precision, flags);
break;
//打印十进制无符号整数
case 'u':
if (qualifier == 'l')
write_num(str, va_arg(args, unsigned long long), 10, field_width, precision, flags);
else
write_num(str, va_arg(args, unsigned int), 10, field_width, precision, flags);
break;
//输出有效字符数量到*ip对应的变量
case 'n':
long long *ip;
if (qualifier == 'l')
ip = va_arg(args, long long *);
else
ip = va_arg(args, int *);
*ip = str - buf;
break;
//对于不识别的控制符,直接输出
default:
*str++ = '%';
if(*fmt)
*str++ = *fmt;
else --fmt;
break;
}
}
*str = '\0';
//返回缓冲区已有字符串的长度。
return str-buf;
}
static void write_num(char *str, long long num, int base, int field_width, int precision, int flags)
{
/**
* @brief
*
* @param str
* @param num
* @param base
* @param field_width
* @param precision
* @param flags
*/
// 首先判断是否支持该进制
if (base < 2 || base > 36)
return 0;
char pad, sign, tmp_num[100];
const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 显示小写字母
if (flags & SMALL)
digits = "0123456789abcdefghijklmnopqrstuvwxyz";
// 设置填充元素
pad = (flags & PAD_ZERO) ? '0' : ' ';
sign = 0;
if (flags & SIGN && num < 0)
{
sign = '-';
num = -num;
}
else
{
// 设置符号
sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
}
// sign占用了一个宽度
if (sign)
--field_width;
if (flags & SPECIAL)
if (base == 16) // 0x占用2个位置
field_width -= 2;
else if (base == 8) // O占用一个位置
--field_width;
int js_num = 0; // 临时数字字符串tmp_num的长度
if (num == 0)
tmp_num[js_num++] = '0';
else
{
num = abs(num);
//进制转换
while (num)
{
tmp_num[js_num++] = num % base; // 注意这里,输出的数字,是小端对齐的。低位存低位
num /= base;
}
}
if (js_num > precision)
precision = js_num;
field_width -= precision;
// 靠右对齐
if (!(flags & LEFT))
while (field_width--)
*str++ = pad;
if (sign)
*str++ = sign;
if (flags & SPECIAL)
if (base == 16)
{
*str++ = '0';
*str++ = digits[33];
}
else if (base == 8)
*str++ = digits[24]; //注意这里是英文字母O或者o
while (js_num < precision)
{
--precision;
*str++ = '0';
}
while (js_num--)
*str++ = tmp_num[js_num];
while (field_width--)
*str++ = ' ';
return str;
}

View File

@ -3,12 +3,14 @@
//
#pragma once
#define PAD_ZERO 1 // 0填充
#define LEFT 2 // 靠左对齐
#define RIGHT 4 //靠右对齐
#define PLUS 8 // 在正数前面显示加号
#define PAD_ZERO 1 // 0填充
#define LEFT 2 // 靠左对齐
#define RIGHT 4 // 靠右对齐
#define PLUS 8 // 在正数前面显示加号
#define SPACE 16
#define SPECIAL 32 //在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
#define SPECIAL 32 // 在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
#define SMALL 64 // 十进制以上数字显示小写字母
#define SIGN 128 // 显示符号位
#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
@ -41,4 +43,17 @@ char buf[4096]; //vsprintf()的缓冲区
* @param args
* @return
*/
int vsprintf(char *buf, const char *fmt, va_list args);
static int vsprintf(char *buf, const char *fmt, va_list args);
/**
* @brief 2~36
*
* @param str
* @param num
* @param base
* @param field_width
* @param precision
* @param flags
*/
static void write_num(char* str, long long num, int base, int field_width, int precision, int flags);