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

default behaviour for std::streams with unsigned

本文关键字:默认 std 带有 unsigned      更新时间:2023-10-16

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

我的假设是:

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.

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

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

那就是说,让我们去标准之地旅行…

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

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

operator<& lt; (bool val);
operator<& lt; (val);
Operator<<(unsigned short val);
operator<& lt; (int val);
操作符<<(unsigned int);
长operator<& lt; (val);
Operator<<(unsigned long val);
操作符<<(long long val);
操作符<<(unsigned long long val);
operator<& lt;(浮动val);
operator<& lt;(双val);
Operator<<(long double val);
(const void* val);

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

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

From $22.4.2.2/5 num_put virtual functions [facet.num.put.virtuals]

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

fmtflags = str.flags();
Fmtflags basefield = (flags &(ios_base:: basefield));
Fmtflags大写= (flags &(ios_base::大写));
Fmtflags floatfield = (flags &(ios_base::实域));
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

From $27.5.3/2 Class ios_base [ios.base]

  1. 它维护几种数据:
    -影响如何解释(格式化)输入序列和如何生成(格式化)输出序列的控制信息;
另一个需要考虑的重要方面是初始化流时的默认标志值是什么。这些列在另一个表中。特别是表128,它描述了调用basic_ios::init()对流的影响。作为参考,std::basic_ios继承自std::ios_basestd::basic_iosstd::basic_ostream的基类,用于提供专用流std::ostream等。 表128 - basic_ios::init() effects
Elements    Flags  
-----------------------------
flags()     skipws | dec

这意味着在init()被调用之后,对flags()的调用应该总是返回与(skipws | dec)相同的值。

把这些放在一起,这意味着无论类型符号如何,新初始化的流都需要以十进制格式格式化整型值。

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