printf 函数 实现 修改了部分原链接错误
增加了输入浮点数和双精度的保留小数点后几位位数功能(%.2f ; %.4l)
增加了负数的支持
增加四舍五入
增加16进制格式:%#x %#X
本文参考以下链接,感谢原创!在他的基础上又进行了追加功能,使更贴近我自己的使用习惯。
原链接:
#include<stdio.h>
#include<stdarg.h>
// unsinged int
void PrintUD(unsigned int Data)
{
//逆递归,逆序处理
if(Data/10!=0)
PrintUD(Data / 10);
putchar(Data % 10 +'0');
}
// int
void PrintD(int Data) {
if(Data<0)
{
putchar('-');
Data = -Data;
}
PrintUD(Data);
}
//float
void PrintF(float Data,int len) {
int Flo;
int I_Data;
int power;
if(Data<0)
{
putchar('-');
Data = -Data;
}
//取出整数部分
I_Data = (int)Data;
power = 10;
//float精度是6位(这里说的是32位编译器),首先先将整数部分去掉
Data -= I_Data;
while(len --) power *= 10;
//取精度
Flo = ((int)(power * Data) + 5)/10; // 四舍五入
//将后面是0的去掉
while(Flo && (Flo%10 == 0)) Flo /= 10;
//打印整数
PrintD(I_Data);
//分割符
putchar('.');
//小数部分
PrintD(Flo);
//其实思路是取出小数变成整数然后打印就行了!
}
//double
void PrintLF(double Data,int len) {
int Flo;
int I_Data;
int power;
if(Data<0)
{
putchar('-');
Data = -Data;
}
//取出整数部分
I_Data = (int)Data;
power = 10;
while(len --) power *= 10;
//float精度是6位(这里说的是32位编译器),首先先将整数部分去掉
Data -= I_Data;
//取精度
Flo = ((int)(power * Data) + 5)/10;
//将后面是0的去掉
while(Flo && (Flo%10 == 0)) Flo /= 10;
//打印整数
PrintD(I_Data);
//分割符
putchar('.');
//小数部分
PrintD(Flo);
//其实思路很简单,就是取出小数变成整数然后打印就行了!
}
//char
void PrintC(char C) {
putchar(C);
}
//char*
void PrintStr(const char* Str) {
while (*Str != '\0') {
putchar(*Str++);
}
}
//0x
void PrintX(unsigned long Num, int Base) {
//判断递归是否小于0
if (Num <= 0) {
return;
}
//逆序递归
PrintX(Num / Base, Base);
//取权值余,这是自然数转进制字符的一种表达式
putchar("0123456789abcdef"[Num%Base]);
}
void PrintP(unsigned int num) {
PrintX(num, 16);
}
void PrintXsmall(unsigned long Num, int Base) {
//判断递归是否小于0
if (Num <= 0) {
return;
}
//逆序递归
PrintXsmall(Num / Base, Base);
//取权值余,这是自然数转进制字符的一种表达式
putchar("0123456789abcdef"[Num%Base]);
}
void PrintXBig(unsigned long Num, int Base) {
//判断递归是否小于0
if (Num <= 0) {
return;
}
//逆序递归
PrintXBig(Num / Base, Base);
//取权值余,这是自然数转进制字符的一种表达式
putchar("0123456789ABCDEF"[Num%Base]);
}
//Printf
int My_Printf(char* ForMat, ...) {
char Line;
int num = 0; // 打印字符数量
int len = 0; // 默认精度
va_list va_l; // 可变参数列表
va_start(va_l, ForMat);
//获取首字符
Line = *ForMat;
while (Line != '\0') {//终结字符
if (Line == '%') {//判断是否遇到格式符号
Line = *++ForMat;//遇到的话递增判断后面的字符是什么
AA: switch (Line) { //校验
case 'c': //char
PrintC(va_arg(va_l, char)); //传递参数
break;
case 's'://str
PrintStr(va_arg(va_l, char*));
break;
case 'd':
PrintD(va_arg(va_l, int));
break;
case 'f'://float 内存中float也是占用8个字节,需要一次性读取8个字节才能读到正确的值,
if(len == 0)len = 6;
PrintF(va_arg(va_l, double),len);
break;
case 'l'://double
if(len == 0) len = 9;
PrintLF(va_arg(va_l, double),len);
break;
case 'p':
PrintP(va_arg(va_l, unsigned int ));
break;
case 'o'://打印八进制
PrintX(va_arg(va_l, int), 8);
break;
case 'x'://打印十六进制
PrintXsmall(va_arg(va_l, int), 16);
break;
case 'X'://打印十六进制
PrintXBig(va_arg(va_l, int), 16);
break;
case '.'://.2f
Line = *++ForMat;
if(Line > '0'&& Line <= '9') len = Line - '0';
Line = *++ForMat;
goto AA;
case '#':
Line = *++ForMat;
if(Line == 'x' || Line == 'X')
{
putchar('0');
putchar(Line);
goto AA;
}
else break;
default://如果不是任何一个格式,则直接打印
putchar('%');
putchar(Line);
break;
}
}
else {
putchar(Line);
}
Line = *++ForMat;
++num;
}
return num;
}
int main() {
My_Printf("%d, %c, %s, %.2f, %.4l, %#x %#X\r\n",-1,'a',"hello world",-0.12467,0.323654,0x12ab,0XABCEF123);
return 0;
}