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

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

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函数没什么复杂逻辑,不做注释。

你可能感兴趣的:(ARM学习,C语言,printf,单片机,移植,打印函数)