注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

c++动态库中对于字符类型变量的格式化处理  

2018-02-03 18:33:04|  分类: C/C++基础 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、问题
在使用stringstream对一个变量进行格式化的时候,发现格式化之后的字符串并不是一个可显示的字符,最后看了半天,发现问题在于这个变量定义的类型是char类型,导致格式化之后数值本身并没有变化。我记得这个问题甚至不是我第一次遇到,这个问题本身是一个很小的问题,但是既然几次遇到都没有什么印象,所以还是在这里简单记录一下吧。
二、gcc使用的stl库中对于字符串流的处理
1、stringstream的定义
gcc-4.1.0\libstdc++-v3\include\std\std_iosfwd.h
  typedef basic_stringstream<char> stringstream; ///< @isiosfwd

2、字符串流的定义
gcc-4.1.0\libstdc++-v3\include\std\std_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.0\libstdc++-v3\include\std\std_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.0\libstdc++-v3\include\bits\ostream.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.0\libstdc++-v3\include\std\std_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.6\stdio-common\vfprintf.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,也就是保持原始值没有变化:

  评论这张
 
阅读(44)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018