带有unsigned的std :: streams的默认行为

时间:2013-06-02 23:06:34

标签: c++ serialization stream

我认为使用“>>”时“<<”流操作符,无符号整数类型被序列化/反序列化为二进制数据,而有符号整数类型被序列化为格式化文本。

我的假设是:

uint32_t a= 17;
int b= 54321;
file_out<<a;   //write 0x00000011 to the file according to some endiannes
file_out<<b;   //write following ASCII characters '5''4''3''2''1' to the file.

我的假设是否在某些标准中明确说明了?如果是,以下哪一项更快?

file_out<<a;

file_out.write((char*)&a,sizeof(uint32_t);

编译器和库MinGW。

特别有点奇怪的是,相同的流类型根据输入类型提供不同的行为。

1 个答案:

答案 0 :(得分:2)

您的C ++标准库副本已损坏正在做一些您未能告诉我们的事情。简而言之,默认的预期行为是以十进制格式输出积分值,而不管类型符号如何。仅考虑类型符号以确保在输出格式设置为十进制时未将无符号值格式化为有符号值。

那就说让我们去标准之地​​......

您感兴趣的关键信息是如何将格式应用于无符号整数。我将尝试突出标准中适用于输出格式的重要部分(关于您的问题)以及如何处理整数。首先看一下operator<<在处理整数类型时的工作原理。这在$ 27.7.3.6.2中定义。

$ 27.7.3.6.2 / 1 - 算术插入器 [ostream.inserters.arithmetic]

  

operator&lt;&lt;(bool val);
  operator&lt;&lt;(short val);
  运算符&lt;&lt;(unsigned short val);
  operator&lt;&lt;(int val);
  运算符&lt;&lt;(unsigned int val);
  运算符&lt;&lt;(long val);
  运算符&lt;&lt;(unsigned long val);
  operator&lt;&lt;(long long val);
  operator&lt;&lt;(unsigned long long val);
  operator&lt;(float val);
  运算符&lt;(&lt;(double val);
  运算符&lt;&lt;(long double val);
  operator&lt;(const void * val);

     

1效果:类num_get&lt;&gt;和num_put&lt;&gt;处理与语言环境相关的数字格式和解析。

num_put实际上负责处理整数值的格式化。

$ 22.4.2.2.2 / 5 num_put虚函数[facet.num.put.virtuals]

  

阶段1:阶段1的第一个操作是确定转换说明符。描述此确定的表使用以下局部变量

     

fmtflags flags = str.flags();
  fmtflags basefield =(flags&amp;(ios_base :: basefield));
  fmtflags uppercase =(flags&amp;(ios_base :: uppercase));
  fmtflags floatfield =(flags&amp;(ios_base :: floatfield));
  fmtflags showpos =(flags&amp;(ios_base :: showpos));
  fmtflags showbase =(flags&amp;(ios_base :: showbase));

     

用于描述阶段1的所有表都是有序的。也就是说,条件为真的第一行适用。没有条件的行是没有任何早期行应用时的默认行为。对于从字符类型以外的整数类型转换,该函数确定表87中所示的积分转换说明符。

          Table 87 — Integer conversions  
State                                stdio equivalent
basefield == ios_base::oct           %o  
(basefield == ios_base::hex) && !uppercase %x  
(basefield == ios_base::hex)         %X  
for a signed integral type           %d  
for an unsigned integral type        %u  

除上述内容外,有两个关键信息。 basefield表示数字格式并且确定已订购basefield很重要,因为它确定值是以十六进制,十进制,八进制等输出。需要流来根据格式标记格式化整数值。请注意,为了使值以十六进制格式化,必须设置ios_base::hex标志

格式标志来自ios_base

$ 27.5.3 / 2类ios_base [ios.base]

  
      
  1. 它保留了几种数据:
       - 控制影响如何解释(格式化)输入序列以及如何生成(格式化)输出序列的信息;
  2.   

需要考虑的另一个重要方面是默认标志值在初始化流时的含义。这些列在不同的表中。具体来说,表128描述了调用basic_ios::init()的效果对流的影响。供参考std::basic_ios继承自std::ios_basestd::basic_iosstd::basic_ostream的基类,用于提供专门的流std::ostream等。

来自$ 27.5.5.3表128 - basic_ios :: init()效果

Elements    Flags  
-----------------------------
flags()     skipws | dec

这意味着在调用init()后,对flags()的调用应始终返回与(skipws | dec)相同的值。

将所有这些放在一起,这意味着需要一个新初始化的流来格式化十进制中的整数值,而不管类型符号

[C ++ 03和C ++ 11之间的关键部分看似相同]