首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 重写sprintf,纯属交流 [已结贴,结贴人:powersuite]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:12:26 楼主
    需要几个理由:
    1、sprintf不能返回格式化结果串的实际长度
    2、sprintf总是把NULL指针格式化为(null)
    3、sprintf的%S格式化只能处理UNICODE到SBCS转换,不能处理UNICODE到MBCS的转换
    4、sprintf处理浮点数,一不小心就拖出个长长的尾巴来

    格式串的规则定义
    //%[flag] [width] [.precision] [{h ¦ l ¦ I64 ¦ L}]type
    //flags: -,+,0,' ',#
    //width:
    //precision
    //type:c,C,d,i,o,u,x,X,e,E,f,g,s,S

    //定义扫描机的状态
    typedef enum{
        XS_SKIP = 0,    //扫描前缀串
        XS_PROC = 1,    //需处理当前格式或前缀串
        XS_FLAG = 2,    //扫描添位符
        XS_WIDTH = 3,    //扫描占宽
        XS_PREC = 4,    //扫描精度
        XS_SIZE= 5,    //扫描整形指示
        XS_TYPE = 6,    //扫描格式符
        XS_TERM = 7    //扫描终止
    }XF_STATUS;

    //定义扫描机的动作
    typedef enum{
        XO_PAUSE = 0,    //暂停
        XO_CONTINUE = 1    //继续
    }XF_OPERA;

    //判断是否添位符
    #define s_is_flag(ch)    ((ch == '0' ¦ ¦ ch == ' ' ¦ ¦ ch == '#')? 1 : 0)
    //判断是否是数字
    #define s_is_digit(ch)    ((ch >= '0' && ch <= '9')? 1 : 0)
    //判断是否是整形指示
    #define s_is_size(ch)    ((*token == 'h' ¦ ¦ *token == 'l')? 1 : 0)
    //判断是否是格式符
    #define s_is_type(ch)    ((ch == 'c' ¦ ¦ ch == 'C' ¦ ¦ ch == 'd' ¦ ¦ ch == 'u' ¦ ¦ ch == 'x' ¦ ¦ ch == 'X' ¦ ¦ ch == 'f' ¦ ¦ ch == 's' ¦ ¦ ch == 'S')? 1 : 0)

    int xsprintf(char* buf,const char* fmt,...)
    {
        va_list arg;
        int total = 0;
        char xf_flag = 0;
        int xf_width = 0;
        int xf_prec = 0;
        char xf_size = 0;
        char xf_type = 0;
        char tk_width[NUM_LEN + 1],tk_prec[NUM_LEN + 1];
        int width_count = 0;
        int prec_count = 0;
        int tk_count = 0;

        //初始化
        XF_STATUS xs = XS_SKIP;
        XF_OPERA xo = XO_PAUSE;

        char* token = (char*)fmt;

        va_start(arg,fmt);

        while(xs != XS_TERM)
        {
            switch(xs)
            {
            case XS_SKIP:
                if(*token == '%' && *(token + 1) != '%')
                {
                    if(!tk_count)
                    {
                        xs = XS_FLAG; //没有前缀串则过渡到格式串扫描
                        xo = XO_CONTINUE;
                    }else
                    {
                        xs = XS_PROC; //有前缀串则先处理前缀串
                        xo = XO_PAUSE;
                    }
                }else if(*token == '\0')
                {
                    xs = XS_PROC; //过渡到处理前缀串
                    xo = XO_PAUSE;
                }else
                {
                    xs = XS_SKIP; //继续前缀串扫描
                    xo = XO_CONTINUE;
                }
                break;
            case XS_FLAG:
                if(s_is_flag(*token))
                {
                    xf_flag = *token;
                    xs = XS_FLAG; //继续占位符扫描
                    xo = XO_CONTINUE;
                }else
                {
                    xs = XS_WIDTH; //过渡到占位宽扫描
                    xo = XO_PAUSE;
                }
                break;
            case XS_WIDTH:
                if(s_is_digit(*token))
                {
                    tk_width[width_count ++] = *token;
                    xs = XS_WIDTH; //继续占位宽扫描
                    xo = XO_CONTINUE;
                }else if(*token == '.')
                {
                    xs = XS_PREC; //过渡到精度扫描
                    xo = XO_CONTINUE;
                }else
                {
                    xs = XS_SIZE; //过渡到整形指示扫描
                    xo = XO_PAUSE;
                }
                break;
            case XS_PREC:
                if(s_is_digit(*token))
                {
                    tk_prec[prec_count ++] = *token;
                    xs = XS_PREC; //继续精度扫描
                    xo = XO_CONTINUE;
                }else
                {
                    xs = XS_SIZE; //过渡到整形指示扫描
                    xo = XO_PAUSE;
                }
                break;
            case XS_SIZE:
                if(s_is_size(*token))
                {
                    xf_size = *token;
                    xs = XS_TYPE; //过渡到格式符扫描
                    xo = XO_CONTINUE;
                }else
                {
                    xs = XS_TYPE; //过渡到格式符扫描
                    xo = XO_PAUSE;
                }
                break;
            case XS_TYPE:
                if(s_is_type(*token))
                {
                    xf_type = *token;
                    xs = XS_PROC; //过渡到处理格式
                    xo = XO_CONTINUE;
                }else
                {
                    xs = XS_PROC; //无效格式符,则过渡到前缀串处理
                    xo = XO_CONTINUE;
                }
                break;
            case XS_PROC:
                if(xf_type) //处理格式串
                {
                    tk_width[width_count] = '\0';
                    xf_width = atoi(tk_width);
                    tk_prec[prec_count] = '\0';
                    xf_prec = atoi(tk_prec);
                    if(!xf_flag)
                        xf_flag = ' ';
                    if(xf_prec && xf_prec > MAX_PREC) //限制最大精度为6
                        xf_prec = MAX_PREC;
                    //处理这个单元的格式串
                    total += _tk_sprintf((buf)? (buf + total) : NULL,xf_flag,xf_width,xf_prec,xf_size,xf_type,&arg);

                    if(*token == '\0')
                        xs = XS_TERM;
                    else
                        xs = XS_SKIP;
                    xo = XO_PAUSE;
                }else //处理前缀串
                {
                    if(buf)
                    {
                        memcpy((void*)(buf + total),(void*)(token - tk_count),tk_count * sizeof(char));
                        buf[total + tk_count] = '\0';
                    }
                    total += tk_count;

                    if(*token == '\0')
                        xs = XS_TERM;
                    else
                        xs = XS_SKIP;
                    xo = XO_PAUSE;
                }
                xf_flag = 0;
                xf_width = 0;
                xf_prec = 0;
                xf_size = 0;
                xf_type = 0;
                width_count = prec_count = tk_count = 0;

                break;
            }

            if(xo == XO_CONTINUE)
            {
                token ++;
                tk_count ++;
            }
        }

        va_end(arg);

        return total;
    }

    50  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:12:521楼 得分:0

    int _tk_sprintf(char* buf,char flag,int width,int prec,char size,char type,va_list* parg)
    {
        wchar_t wch;
        char tmp[NUM_LEN + 1] = {0};
        int len,pos;
        char sign;
        short s;
        int i;
        unsigned short us;
        unsigned int ui,xi;
        double dbl;
        char* sz;
        wchar_t* wsz;

        switch(type)
        {
        case 'c':
            if(buf)
            {
                buf[0] = va_arg(*parg,char);
                buf[1] = '\0';
            }
            return 1;
        case 'C':
            wch = va_arg(*parg,wchar_t);
            len = WideCharToMultiByte(CP_ACP,0,&wch,1,NULL,0,NULL,NULL);
            if(buf)
            {
                WideCharToMultiByte(CP_ACP,0,&wch,1,buf,len,NULL,NULL);
                buf[len] = '\0';
            }
            return len;
        case 'd':
            len = 0;
            sign = 0;
            pos = 0;
            if(size == 'h')
            {
                s = va_arg(*parg,short);
                if(s < 0)
                {
                    sign = '-';
                    s = 0 - s;
                }
               
                while(s)
                {
                    tmp[len ++] = s % 10 + 48;
                    s /= 10;
                }
            }else
            {
                i = va_arg(*parg,int);
                if(i < 0)
                {
                    sign = '-';
                    i = 0 - i;
                }

                while(i)
                {
                    tmp[len ++] = i % 10 + 48;
                    i /= 10;
                }
            }
            if(sign)
            {
                if(buf)
                    buf[pos] = sign;
                pos ++;
                width --;
            }
            width -= len;
            while(width > 0)
            {
                if(buf)
                    buf[pos] = '0';
                pos ++;
                width --;
            }
            while(len--)
            {
                if(buf)
                    buf[pos] = tmp[len];
                pos ++;
            }
            if(buf)
                buf[pos] = '\0';
            return pos;
        case 'u':
            len = 0;
            sign = 0;
            pos = 0;
            if(size == 'h')
            {
                us = va_arg(*parg,unsigned short);
                while(us)
                {
                    tmp[len ++] = us % 10 + 48;
                    us /= 10;
                }
            }else
            {
                ui = va_arg(*parg,unsigned int);
                while(ui)
                {
                    tmp[len ++] = ui % 10 + 48;
                    ui /= 10;
                }
            }
            width -= len;
            while(width > 0)
            {
                if(buf)
                    buf[pos] = '0';
                pos ++;
                width --;
            }
            while(len--)
            {
                if(buf)
                    buf[pos] = tmp[len];
                pos ++;
            }
            if(buf)
                buf[pos] = '\0';
            return pos;
        case 'x':
        case 'X':
            len = 0;
            sign = 0;
            pos = 0;

            if(buf)
            {
                buf[0] = '0';
                buf[1] = type;
            }
            pos += 2;

            ui = va_arg(*parg,unsigned int);
            while(ui)
            {
                us = ui % 16;
                if(type == 'x')
                    tmp[len ++] = (us < 9)? (us + 48) : (us + 87);
                else
                    tmp[len ++] = (us < 9)? (us + 48) : (us + 55);
                ui /= 16;
            }

            width -= len;
            while(width > 0)
            {
                if(buf)
                    buf[pos] = '0';
                pos ++;
                width --;
            }
            while(len--)
            {
                if(buf)
                    buf[pos] = tmp[len];
                pos ++;
            }
            if(buf)
                buf[pos] = '\0';
            return pos;
        case 'f':
            len = 0;
            sign = 0;
            pos = 0;

            dbl = va_arg(*parg,double);
            if(dbl < 0)
            {
                sign = '-';
                dbl = 0 - dbl;
            }

            xi = (int)dbl;

            dbl -= (double)xi;
            if(prec)
                s = (short)prec;
            else
                s = MAX_PREC;
            while(s--)
                dbl *= 10.0;

            ui = (int)floor(dbl + 0.5);

            if(!prec)
            {
                while(!(ui % 10))
                    ui /= 10;
            }

            while(ui)
            {
                tmp[len ++] = ui % 10 + 48;
                ui /= 10;
            }
            if(len)
                tmp[len ++] = '.';

            while(xi)
            {
                tmp[len ++] = xi % 10 + 48;
                xi /= 10;
                width --;
            }

            if(sign)
            {
                if(buf)
                    buf[pos] = sign;
                pos ++;
                width --;
            }

            while(width > 0)
            {
                if(buf)
                    buf[pos] = '0';
                pos ++;
                width --;
            }

            while(len--)
            {
                if(buf)
                    buf[pos] = tmp[len];
                pos ++;
            }
            if(buf)
                buf[pos] = '\0';
            return pos;
        case 's':
            len = 0;
            sign = 0;
            pos = 0;

            sz = va_arg(*parg,char*);
            if(!sz)
            {
                if(buf)
                    buf[pos] = '\0';
                return pos;
            }
         
            len = strlen(sz);
            width -= len;
            while(width > 0)
            {
                if(buf)
                    buf[pos] = flag;
                pos ++;
                width --;
            }

            if(buf)
                memcpy((void*)(buf + pos),(void*)sz,len * sizeof(char));
            pos += len;
            if(buf)
                buf[pos] = '\0';
            return pos;
        case 'S':
            len = 0;
            sign = 0;
            pos = 0;

            wsz = va_arg(*parg,wchar_t*);
            if(!wsz)
            {
                if(buf)
                    buf[pos] = '\0';
                return pos;
            }

            ui = wcslen(wsz);
            len = WideCharToMultiByte(CP_ACP,0,wsz,ui,NULL,0,NULL,NULL);
            width -= len;
            while(width > 0)
            {
                if(buf)
                    buf[pos] = flag;
                pos ++;
                width --;
            }
         
            if(buf)
                WideCharToMultiByte(CP_ACP,0,wsz,ui,buf + pos,len,NULL,NULL);
            pos += len;
            if(buf)
                buf[pos] = '\0';
            return pos;
        }
        return 0;
    }

    这样:
    int len = xspritf(NULL,"这次要分配%d个字节,18)可以返回结果串的精确长
    xsprintf(buf,"a=%s",NULL)不会格式成a=(null)
    xsprintf(buf,"a=%f",8.0/9.0)不会返回长长的尾巴了
    xsprintf(buf,"%svs%S","俄罗斯",L"荷兰")可以处理MBCS和UNICODE
    少了些麻烦
    不过没有支持[e,E,f,g,]的格式符,抱歉了
    UICODE版的xwprintf道理也是一样的,就不贴出来了
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:13:242楼 得分:5
    支持楼主                                  .
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:15:373楼 得分:5
    不错!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:15:464楼 得分:5
    楼主好强,崇拜中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:20:295楼 得分:5
    不错,不过不用sprintf了
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:23:246楼 得分:5
    弱弱的问一句cout行不行?不过还是佩服LZ
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 16:30:417楼 得分:5
    强!真正的程序员!感谢lz。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 17:04:598楼 得分:4
    支持
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-24 17:21:559楼 得分:4
    引用 2 楼 baihacker 的回复:
    支持楼主                                  .

    进来学习地o(∩_∩)o...
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 02:16:0510楼 得分:4
    引用 9 楼 jillnicky 的回复:
    引用 2 楼 baihacker 的回复:
    支持楼主                                  .

    进来学习地o(∩_∩)o...
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 08:23:4111楼 得分:4
    楼主这种学习方法值得推荐
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 08:29:1312楼 得分:4
    up
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved