-2

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

我的假设是:

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。

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

4

1 回答 1

2

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

也就是说,让我们去标准地旅行吧……

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

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

运算符<<(布尔值);
运算符<<(短值);
运算符<<(无符号短值);
运算符<<(int val);
运算符<<(无符号整数值);
运算符<<(long val);
运算符<<(无符号长值);
运算符<<(long long val);
运算符<<(unsigned long long val);
运算符<<(浮点值);
运算符<<(双值);
运算符<<(long double val);
运算符<<(const void* val);

1 效果:类 num_get<> 和 num_put<> 处理依赖于语言环境的数字格式和解析。

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

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

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

fmtflags 标志 = str.flags() ;
fmtflags basefield = (flags & (ios_base::basefield));
fmtflags 大写 = (flags & (ios_base::uppercase));
fmtflags floatfield = (flags & (ios_base::floatfield));
fmtflags showpos = (flags & (ios_base::showpos));
fmtflags showbase = (flags & (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. 它维护几种数据:
    — 影响如何解释(格式化)输入序列和如何生成(格式化)输出序列的控制信息;

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

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

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

这意味着 afterinit()被调用的调用flags()应该总是返回一个与 相同的值(skipws | dec)

把这一切放在一起,这意味着需要一个新初始化的流来格式化十进制整数值,而不管类型 sign

[C++03 和 C++11 的关键部分似乎相同]

于 2013-06-03T01:34:39.910 回答