首页 > 其他分享 >Sword vsprintf自定义实现

Sword vsprintf自定义实现

时间:2023-02-07 22:57:53浏览次数:33  
标签:自定义 ++ vsprintf ui64 unsigned long char Sword buf

/* vsprintf自定义实现 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <stdarg.h>
#include <math.h>

typedef struct {
    size_t           len;
    unsigned char* data;
} gtc_str_t;

#define GTC_INT32_LEN             (sizeof("-2147483648") - 1)
#define GTC_INT64_LEN             (sizeof("-9223372036854775808") - 1)
#define GTC_MAX_UINT32_VALUE      (unsigned int) 0xffffffff

#define gtc_min(val1, val2)       ((val1 > val2) ? (val2) : (val1))
#define gtc_string(str)           { sizeof(str) - 1, (unsigned char *) str }
#define gtc_cpymem(dst, src, n)   (((unsigned char *) memcpy(dst, src, n)) + (n))

//int mprintf(unsigned char* buf, const char* fmt, ...) __attribute__((format(printf,2,3)));

static unsigned char* gtc_sprintf_num(unsigned char* buf, unsigned char* last, unsigned long long ui64, unsigned int hexadecimal)
{
    unsigned char        * p, temp[GTC_INT64_LEN + 1] = { 0 };
    size_t                 len;
    unsigned int           ui32;
    static unsigned char   hex[] = "0123456789abcdef";
    static unsigned char   HEX[] = "0123456789ABCDEF";

    // 1.参数校验

    p = temp + GTC_INT64_LEN;
    if (0 == hexadecimal)
    {
        // 非十六进制数值处理

        if (ui64 < GTC_MAX_UINT32_VALUE)
        {
            /*
            设计说明:
                为什么无符号32位和无符号64位需要分开处理?
                因为在某些平台上32位除法和64除法不一样,为了提升32位除法性能,因此需要分开处理
            */
            ui32 = (unsigned int)ui64;
            do {
                *--p = (unsigned char)(ui32 % 10 + '0');
            } while (ui32 /= 10);
        }
        else
        {
            do {
                *--p = (unsigned char)(ui64 % 10 + '0');
            } while (ui64 /= 10);
        }
        
    }
    else if (1 == hexadecimal)
    {
        do {

            /* the "(uint32_t)" cast disables the BCC's warning */
            *--p = hex[(unsigned int)(ui64 & 0xf)];

        } while (ui64 >>= 4);
    }
    else
    {
        /* hexadecimal == 2 */
        do {

            /* the "(uint32_t)" cast disables the BCC's warning */
            *--p = HEX[(unsigned int)(ui64 & 0xf)];

        } while (ui64 >>= 4);
    }
    
    // 计算拷贝字符串长度
    len = temp + GTC_INT64_LEN - p;

    if (buf + len > last) {
        len = last - buf;
    }

    return gtc_cpymem(buf, p, len);
}

static unsigned char* gtc_vslprintf(unsigned char* buf, unsigned char* last, const char* fmt, va_list args)
{
    double                f;
    int                   long_type, ch;
    long long             i64;
    unsigned long long    ui64, frac, scale;
    gtc_str_t*            v;
    size_t                len;
    unsigned char       * p;

    // 1.参数校验

    // 2.格式化
    while (*fmt && buf < last) 
    {
        if ('%' == *fmt)
        {
            fmt++;

            // 初始化
            long_type = 0;
            i64 = 0;
            ui64 = 0;

            // 处理ld% lu% %lf类似于多个格式化标记
            for (;;)
            {
                switch (*fmt)
                {
                case 'l':
                    // 长类型标记
                    long_type = 1;
                    fmt++;
                    break;
                default:
                    break;
                }

                break;
            }

            switch (*fmt)
            {
            case 'u':
                if (long_type)
                {
                    // %lu 无符号长整型
                    ui64 = (unsigned long long)va_arg(args, unsigned long long);
                }
                else
                {
                    // %u 无符号整型
                    ui64 = (unsigned long long)va_arg(args, unsigned int);
                }
                
                // 数字格式化
                buf = gtc_sprintf_num(buf, last, ui64, 0);

                fmt++;
                continue;
            case 'd':
                if (long_type)
                {
                    // %ld 有符号长整型
                    i64 = (long long)va_arg(args, long long);
                } 
                else
                {
                    // %d 有符号整型
                    i64 = (long long)va_arg(args, int);
                }

                // 负数处理
                if (i64 < 0) 
                {
                    *buf++ = '-';
                    i64 = -i64;
                }

                // 数字格式化
                ui64 = (unsigned long long)i64;
                buf = gtc_sprintf_num(buf, last, ui64, 0);

                fmt++;

                continue;

            case 'c':
                // 字符
                /*
                知识补充:
                    va_arg不支持获取char类型,需要用int来代替
                */
                ch = va_arg(args, int);
                *buf++ = (unsigned char)(ch & 0xff);

                fmt++;

                continue;

            case 'f':

                f = va_arg(args, double);

                if (f < 0) {
                    *buf++ = '-';
                    f = -f;
                }

                // 整数部分提取
                ui64 = (unsigned long long)f;
                // 数字转字符串
                buf = gtc_sprintf_num(buf, last, ui64, 0);

                // 根据实测,printf是保留小数点后面6位有效数字
                scale = (unsigned long long)pow(10, 6);

                // 0.5为了四舍五入
                frac = (unsigned long long)((f - (double)ui64) * scale + 0.5);
                if (frac)
                {
                    // 获取真实精度
                    while (!frac%10) 
                    {
                        frac /= 10;
                    }

                    // 字符串增加小数点
                    if (buf < last) {
                        *buf++ = '.';
                    }

                    // 数字转字符串
                    buf = gtc_sprintf_num(buf, last, frac, 0);
                }

                fmt++;

                continue;

            case 'V':
                /*
                设计说明:
                    注意%V的特殊用法,这个值得记录
                */
                v = va_arg(args, gtc_str_t*);

                len = gtc_min(((size_t)(last - buf)), v->len);
                buf = gtc_cpymem(buf, v->data, len);
                fmt++;

                continue;

            case 'x':
                ui64 = (unsigned long long)va_arg(args, unsigned int);

                // 数字格式化
                buf = gtc_sprintf_num(buf, last, ui64, 1);

                fmt++;

                continue;

            case 'X':
                ui64 = (unsigned long long)va_arg(args, unsigned int);

                // 数字格式化
                buf = gtc_sprintf_num(buf, last, ui64, 2);

                fmt++;

                continue;

            case '%':

                *buf++ = '%';
                fmt++;

                continue;

            case 'p':

                ui64 = (unsigned long long)va_arg(args, void*);

                *buf++ = '0';
                *buf++ = 'x';

                // 数字格式化
                buf = gtc_sprintf_num(buf, last, ui64, 2);

                fmt++;

                continue;

            case 's':
                p = va_arg(args, unsigned char*);
                while (*p && buf < last) {
                    *buf++ = *p++;
                }

                fmt++;

                continue;

            default:
                *buf++ = *fmt++;

                continue;
            }
        }
        else
        {
            // 拷贝非格式化字符
            *buf++ = *fmt++;
        }
    }

    return buf;

}

/*
知识补充:
    __attribute__ format
    该__attribute__属性可以给被声明的函数加上类似于printf或scanf的特征,他可以使编辑器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。
    format的语法格式为
    format(archetype, string-index, first-to-check)
    format属性告诉编译器,按照printf,scanf,strftime,strfmon的参数表格式规则对该函数的参数进行检查。
    archetype指定是哪种风格
    string-index指定传入函数的第几个参数是格式化字符串
    first-to-check指定从函数的第几个参数开始按上述规则进行检查
    注意:当该函数是C++类中成员属性时,需要考虑this指针问题。
    
    使用方式
    1.函数声明
    int mprintf(unsigned char* buf, const char* fmt, ...) __attribute__((format(printf,2,3)));
    2.函数定义
    __attribute__((format(printf, 2, 3))) int mprintf(unsigned char* buf, const char* fmt, ...){}
    以上两种方式任选其一即可
*/
__attribute__((format(printf, 2, 3))) int mprintf(unsigned char* buf, const char* fmt, ...)
{
    int         ret = 0;
    va_list     ap;

    // 1.参数校验
    if (NULL == buf)
    {
        ret = -1;
        return ret;
    }

    // 2.初始化宏变量
    va_start(ap, fmt);

    // 3.格式化字符串
    gtc_vslprintf(buf, (void*)-1, fmt, ap);

    // 4.结束
    va_end(ap);

    return ret;
}

void test()
{
    unsigned char buf[2024] = { 0 };
    gtc_str_t str = gtc_string("world");
    int a1 = 123;
    int a2 = -456;
    float f1 = 18.3;
    double f2 = 23.456;
    unsigned int u1 = 302;
    unsigned long long u2 = 348;

    //mprintf(buf, "number is %d | negative number is %d | float number is %f | double number is %f | unsigned number is %u | unsigned long long number is %u | hexadecimal is %x | hexadecimal is %X | pointer is %p | hello %V | character is %%", a1, a2, f1, f2, u1, u2, u1, u1, &u1, &str);

    mprintf(buf, "%s with you.", "fly");

    printf("%s\n", buf);
}

int main()
{
    test();
    return 0;
}

 

标签:自定义,++,vsprintf,ui64,unsigned,long,char,Sword,buf
From: https://www.cnblogs.com/zhanggaofeng/p/17100076.html

相关文章

  • Vite+Vue3+TS 自定义全局组件,无法不能高亮解析的解决办法
    检查package.json中的devDependencies是否安装@vue/runtime-core依赖,没有的话,安装后重启VSCode一、安装依赖$yarnadd@vue/runtime-core-D$yarnaddunplugin-vue-......
  • ESL中如何自定义事件及自定义事件的监听
    虽然freeswitch已经内置了一些标识的事件,比如:CHANNEL_CREATE(发起呼叫时触发),CHANNEL_HANGUP_COMPLETE(电话挂断时触发)...,但是有时候我们想根据业务需求,新增一些自定义的事......
  • java对自定义类型的两种排序方法(Arrays.sort和Collections.sort)
    前言对普通基本类型的数组或者集合sort都有相应的排序方法(从小到大),但是对于我们自定义的类型,就需要重新定义比较器,这里介绍对对象数组排序的Arrays.sort和对集合排序的Coll......
  • 使用自定义指令fofo, 让输入框自动聚焦
    使用自定义指令fofo,让输入框自动聚焦判断指令所在的标签importVuefrom'vue'//插件对象(必须有install方法,才可以注入到Vue.use中)exportdefault{instal......
  • How to Turn Off Dictionary Checking for Password Changes
     Fedora:modify/etc/pam.d/system-auth  fedora采用authselect管理authorization Ubuntu:modify/etc/pamd.d/common-password ......
  • 灵活又简便,效率提升快,来了解下自定义表单工具!
    选择低代码开发平台,需要看准服务商、产品、服务保障等条件。只有认准专业的开发平台服务商,才能拥有一整套完善的低代码平台解决方案,才能帮助企业最大限度提升办公协作效率,......
  • elasticsearch添加自定义用户
    添加用户和角色curl--insecure-uelastic:Transfar@2022-XPOST'https://192.168.30.149:9200/_security/user/esuer?pretty'-H'Content-Type:application/json'......
  • avalonia自定义弹窗
    对于使用avalonia的时候某些功能需要到一些提示,比如异常或者成功都需要对用户进行提示,所以需要单独实现弹窗功能,并且可以自定义内部组件,这一期将手动实现一个简单的小弹窗,......
  • logic-flow自定义节点
    目前基于需要选择任一一种基本节点类型(如rect、circle、polygon等)来继承新建节点文件(例:CustomCircle.js)//CustomCircle.jsimport{CircleNode,CircleNodeModel}fr......
  • avalonia实现自定义小弹窗
    对于使用avalonia的时候某些功能需要到一些提示,比如异常或者成功都需要对用户进行提示,所以需要单独实现弹窗功能,并且可以自定义内部组件,这一期将手动实现一个简单的小弹窗,......