可移植的单片机printf(print by format)函数实现

一个有趣的实验:
这里写图片描述
说明%号一出现要么被”吃掉”要么他会终止与f,d,s。
那么再加以大胆猜想:
假设
int sprintf(const char *format, …);
当然我们需要可变参数标准库的支持因为调用的可变参数的方法。当读取到了一个%号,就开始匹配fds中的任意一个,每种的处理方式都不一样。分别是:
char *itoc(int value);
char *ftoc(float value);
再将转换出来的字符串一段段拼接(strcat)起来就成了我们需要输出到串口的字符串。
这里写图片描述

void printf(const char *format, ...)
{
    va_list list;
    va_start(list, format);
    char *pFormat = format;
    char *pInner;
    char data[256] = {0};
    int dataIndex = 0;
    while ('\0' != *pFormat)//整个fomat的匹配结束条件
    {
        if (*pFormat == '%')//是%就开始迎接下一个符号
        {
            pInner = pFormat;
            while ((*pInner != 'd') && (*pInner != 'f') && (*pInner != 's') && (*pInner != '\0')) //到达了一个%---x对,开始处理
            {
                pInner++;
            }
            pFormat = pInner+1;//使索引指针指向到下一个字符
            switch (*pInner)//进行%-x对替换
            {
            case 'f':
                while (*pInner != '.' && *pInner != '%')//往回索引,看能不能找到类似1.5f中的点
                {
                    pInner--;
                }
                if (*pInner == '.')//找到了小数点,取点前为整数长度,取点后位小数精度
                {
                    strcat(data, ftoc(va_arg(list, double), (int)(*(pInner - 1) - 0x30), (int)(*(pInner + 1) - 0x30)));
                }
                if (*pInner == '%')//索引回到了%说明没指定浮点精度,使用默认的3.3f精度
                {
                    strcat(data, ftoc(va_arg(list, double), 3,3));
                }
                break;
            case 'd':
                strcat(data, itoc(va_arg(list, int)));
                break;
            case 's':
                strcat(data, va_arg(list, char*));
                break;
            default:
                break;
            }

            while (data[dataIndex] != '\0')//将dataIndex一直与字符串尾同步
            {
                dataIndex++;
            }
        }
        else//不是%一直把当前的字符复制到目标中
        {
            data[dataIndex] = *pFormat;
            data[++dataIndex ] = '\0';//封尾方便粘贴
        }
        if (*pFormat == '\0')//匹配有%没有dsf收尾的情况
            break;
    }
    //puts(data);//该方法由单片机通讯实现,在不同的单片机不同的使用情景下情况不同,可能是打印到显示屏,也可能是串口输出到上位机等等。
}



char *itoc(const int value)//整形转字符串
{
    char debuff[128];
    int a = value, index=0 ,deIndex = 0;
    while ((a / 10) != 0)
    {
        debuff[deIndex++] = a % 10 + 0x30;
        a /= 10;
    } 
    debuff[deIndex] = a % 10 + 0x30;
    while (deIndex >= 0)
    {
        itocBuff[index++] = debuff[deIndex--];
    }
    itocBuff[index] = '\0';
    return itocBuff;
}

char *ftoc(float value,int integer,int decimals)//浮点转字符串
{
    unsigned int a;
    int decimalsCp = decimals;
    char debuff[128];
    int index = 0, deIndex = 0;
    while (decimalsCp)
    {
        value *= 10;
        decimalsCp--;
    }

    a = (int)value;
    while (decimals--)
    {
        debuff[deIndex++] = a%10 + '0';
        a /= 10;
    }
    debuff[deIndex++] = '.';
    while (integer--)
    {
        debuff[deIndex++] = a % 10 + '0';
        a /= 10;
    }
    while (deIndex--)
    {
        ftocBuff[index++] = debuff[deIndex];
    }
    ftocBuff[index] = '\0';
    return ftocBuff;
}

void strcat(char *target, const char *source)//字符串拼接
{
    while (*target != '\0')
    {
        target++;
    }
    while (*source != '\0')
    {
        *target++ = *source++;
    }
    *target = '\0';
}

写在后面,实现了一个简单的模板功能还比较粗糙,适合简单字符串穿插一些数字和字符串,具体细节还需要慢慢完善。
附注:
1.没有选择递归的方法直接生成正序的字符串而是使用的反序生成在倒序装入的方法得到了ftoc和itoc的结果,两个函数方法相同,一并解释。
2.srtcat函数没什么复杂逻辑,不做注释。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值