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,也就是保持原始值没有变化:
原文地址:https://www.cnblogs.com/tsecer/p/10488014.html