zoukankan      html  css  js  c++  java
  • c++动态库中对于字符类型变量的格式化处理

    一、问题
    在使用stringstream对一个变量进行格式化的时候,发现格式化之后的字符串并不是一个可显示的字符,最后看了半天,发现问题在于这个变量定义的类型是char类型,导致格式化之后数值本身并没有变化。我记得这个问题甚至不是我第一次遇到,这个问题本身是一个很小的问题,但是既然几次遇到都没有什么印象,所以还是在这里简单记录一下吧。
    二、gcc使用的stl库中对于字符串流的处理
    1、stringstream的定义
    gcc-4.1.0libstdc++-v3includestdstd_iosfwd.h
      typedef basic_stringstream<char>  stringstream; ///< @isiosfwd
     
    2、字符串流的定义
    gcc-4.1.0libstdc++-v3includestdstd_ostream.h
    namespace std
    {
      // [27.6.2.1] Template class basic_ostream
      /**
       *  @brief  Controlling output.
       *
       *  This is the base class for all output streams.  It provides text
       *  formatting of all builtin types, and communicates with any class
       *  derived from basic_streambuf to do the actual output.
      */
      template<typename _CharT, typename _Traits>
        class basic_ostream : virtual public basic_ios<_CharT, _Traits>
        {
    ……
          template<typename _Traits2>
            friend basic_ostream<char, _Traits2>&
            operator<<(basic_ostream<char, _Traits2>&, const char*);
     
          template<typename _CharT2, typename _Traits2>
            friend basic_ostream<_CharT2, _Traits2>&
            operator<<(basic_ostream<_CharT2, _Traits2>&, const char*);
     
    gcc-4.1.0libstdc++-v3includestdstd_iomanip.h
     
      // Specialization
      template <class _Traits> 
        basic_ostream<char, _Traits>&
        operator<<(basic_ostream<char, _Traits>& __out, char __c);
     
      // Signed and unsigned
      template<class _Traits>
        basic_ostream<char, _Traits>&
        operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
        { return (__out << static_cast<char>(__c)); }
     
    3、功能的实现
    gcc-4.1.0libstdc++-v3includeitsostream.tcc
     
      // Specializations.
      template <class _Traits>
        basic_ostream<char, _Traits>&
        operator<<(basic_ostream<char, _Traits>& __out, char __c)
        {
          typedef basic_ostream<char, _Traits> __ostream_type;
          typename __ostream_type::sentry __cerb(__out);
          if (__cerb)
    {
      try
        {
          const streamsize __w = __out.width();
          streamsize __len = 1;
          char* __cs = &__c;
          if (__w > __len)
    {
      __cs = static_cast<char*>(__builtin_alloca(__w));
      __pad<char, _Traits>::_S_pad(__out, __out.fill(), __cs,
           &__c, __w, __len, false);
      __len = __w;
    }
          __out._M_write(__cs, __len);
          __out.width(0);
        }
      catch(...)
        { __out._M_setstate(ios_base::badbit); }
    }
          return __out;
         }
     
    4、_M_write的实现
    gcc-4.1.0libstdc++-v3includestdstd_ostream.h
          // Core write functionality, without sentry.
          void
          _M_write(const char_type* __s, streamsize __n)
          {
    streamsize __put = this->rdbuf()->sputn(__s, __n);
    if (__put != __n)
      this->setstate(ios_base::badbit);
          }
     
    三、C标准库中的printf对于该内容的处理
     
    1、格式化字符的处理位置
     
    glibc-2.6stdio-commonvfprintf.c
    /* The function itself.  */
    int
    vfprintf (FILE *s, const CHAR_T *format, va_list ap)
    {
    ……
    # define process_string_arg(fspec)
        LABEL (form_character):       
          /* Character.  */       
          if (is_long)       
    goto LABEL (form_wcharacter);       
          --width; /* Account for the character itself.  */       
          if (!left)       
    PAD (' ');       
          if (fspec == NULL)       
    outchar ((unsigned char) va_arg (ap, int)); /* Promoted.  */       
          else       
    outchar ((unsigned char) args_value[fspec->data_arg].pa_int);       
          if (left)       
    PAD (' ');       
          break;
     
    2、outchar的定义内容
     
    #define outchar(Ch)       
      do       
        {       
          register const INT_T outc = (Ch);       
          if (PUTC (outc, s) == EOF)       
    {       
      done = -1;       
      goto all_done;       
    }       
          else       
    ++done;       
        }       
      while (0)
     
    PUTC宏的定义
    # define PUTC(C, F) _IO_putc_unlocked (C, F)
     
    也就是没有变化,直接将该内容添加到输出流中。从而对于char类型的变量直接按照原始内容放在了输出字节流中
    #define _IO_putc_unlocked(_ch, _fp)
       (_IO_BE ((_fp)->_IO_write_ptr >= (_fp)->_IO_write_end, 0)
        ? __overflow (_fp, (unsigned char) (_ch))
        : (unsigned char) (*(_fp)->_IO_write_ptr++ = (_ch)))
     
    四、总结
     
    结论在于,当你使用标准字节流的时候,如果使用的是 << 操作符,这个时候如果变量不小心定义为了 char类型,那么这个输出结构可能就不是一个可以显示的字符。
     
    下面是代码例子
    tsecer@harry: cat outchar.cpp 
    #include <sstream>
    #include <stdio.h>
    #include <iostream>
     
    int main()
    {
            int i = 1;
            char c = 1;
            std::stringstream ssi, ssc;
     
            ssi<<"|"<<i<<"|";
            ssc<<"|"<<c<<"|";
     
            std::cout<<ssi.str()<<std::endl;
            std::cout<<ssc.str()<<std::endl;
            return 0;
    }
     
    tsecer@harry: g++ outchar.cpp 
    tsecer@harry: ./a.out | hexdump -C 
    00000000  7c 31 7c 0a 7c 01 7c 0a                           ||1|.|.|.|
    00000008
    tsecer@harry: 
    可以看到,内码输出还是为01,也就是保持原始值没有变化:
  • 相关阅读:
    android 微信(5.3)聊天UI的布局思考
    android 屏幕适配
    不同Activity之间的动画切换
    Freemarker 进行字符串截取
    如何使带背景图片的Button按钮中的文字居中偏上显示
    关于在IE-8下 button的背景图片不能正确显示的问题
    android Xmpp+openfire 消息推送 :SASL authentication failed using mechanism DIGEST-MD5
    Android运行出现“java.io.IOException: 您的主机中的软件放弃了一个已建立的连接。”
    计算机网络
    Java基础-3
  • 原文地址:https://www.cnblogs.com/tsecer/p/10488014.html
Copyright © 2011-2022 走看看