cout << std::ios::hex 是做什么的?
What does cout << std::ios::hex do?
这个问题来自于我最近遇到的一个bug。我试图将一些整数值保存为十六进制文件。例如,这是我应该做的:
cout << std::hex << value << endl; // (1)
但是我错误地使用它如下:
cout << std::ios::hex << value << endl; // (2)
编译器没有报错,但显然结果不正确。我随机尝试了几个值,似乎 (2) 实际上给出了部分正确的结果,只是它附加了 800 作为前缀。我不明白 800 是从哪里来的,而且我在任何地方都看不到很好的参考。谁能解释幕后发生的事情?
cout << std::hex << 255 << endl; // output: FF
cout << std::ios::hex << 255 << endl; // output: 800ff
cout << std::hex << 135 << endl; // output: 87
cout << std::ios::hex << 135 << endl; // output: 80087
cout << std::hex << 11 << endl; // output: b
cout << std::ios::hex << 11 << endl; // output: 800b
这实际上是std::ios_base::hex
。这是一个实现定义的位掩码。在内部,流有一个名为 fmtflags
的整数,它存储格式的当前状态。
在您的实现中,hex
是标志 0x800
。其他flags会表示是否处于科学计数模式,boolalpha
是否开启等
std::hex
函数在 fmtflags
中设置 std::ios_base::hex
标志。
因此您的输出是此标志的整数值(自您之前发送 std::hex
以来为十六进制)。
std::hex
是一个特殊对象,当使用 operator<<
、
应用于流时
sets the basefield of the stream str
to hex as if by calling str.setf(std::ios_base::hex, std::ios_base::base field)
std::ios::hex
(又名 std::ios_base::hex
)是传递给 setf
方法的实际位掩码值。它的值是实现定义的,在你的情况下它似乎是 0x800
。
std::hex
是一个 操纵器,即它是一个具有特定签名的函数:
std::ios_base& hex(std::ios_base& stream) {
stream.setf(std::ios_base::hex, std::ios_base::basefield);
return stream;
}
为流处理操纵器定义了一些特殊的输出运算符。对于对 std::ios_base
的引用进行操作的版本有(忽略运算符实际上是一个函数模板):
std::ostream& operator<< (std::ostream& out, std::ios_base&(*manip)(std::ios_base&));
当与流一起使用时,将调用操纵器函数并设置特定格式标志,在本例中为 std::ios_base::hex
(这就是 std::ios::hex
的实际定义方式)。由于 std::ios_base::hex
是一组标志的成员(其他是 std::ios_base::dec
和 std::ios_base::oct
)设置它还需要清除组中任何潜在的其他标志。因此,使用掩码 (std::ios_base::basefield
) 调用 setf()
以清除任何其他可能设置的标志。
格式标志 std::ios_base::fmtflags
是位掩码类型。值 std::ios_base::hex
是值之一。格式化时你会得到一些数字,很可能是 2 的幂(但是,它不一定是 2 的幂)。您看到的值只是使用十六进制表示法打印的 0x800
(即 2048):设置任何格式标志(width()
除外)是 sticky,即,它们会一直保留到标志被取消设置为止。如果您想查看值 2048(对于您正在使用的实现),您可以使用
std::cout << std::dec << std::ios_base::hex << "\n"; // 2048
std::cout << std::hex << std::ios_base::hex << "\n"; // 800
std::cout << std::showbase << std::ios_base::hex << "\n"; // 0x800
最后一行设置标志 showbase
表示整数值的基数,前缀为:
- 无前缀 => 十进制
- 前导
0x
=> 十六进制
- 前导
0
(但没有x
)=>八进制
这个问题来自于我最近遇到的一个bug。我试图将一些整数值保存为十六进制文件。例如,这是我应该做的:
cout << std::hex << value << endl; // (1)
但是我错误地使用它如下:
cout << std::ios::hex << value << endl; // (2)
编译器没有报错,但显然结果不正确。我随机尝试了几个值,似乎 (2) 实际上给出了部分正确的结果,只是它附加了 800 作为前缀。我不明白 800 是从哪里来的,而且我在任何地方都看不到很好的参考。谁能解释幕后发生的事情?
cout << std::hex << 255 << endl; // output: FF
cout << std::ios::hex << 255 << endl; // output: 800ff
cout << std::hex << 135 << endl; // output: 87
cout << std::ios::hex << 135 << endl; // output: 80087
cout << std::hex << 11 << endl; // output: b
cout << std::ios::hex << 11 << endl; // output: 800b
这实际上是std::ios_base::hex
。这是一个实现定义的位掩码。在内部,流有一个名为 fmtflags
的整数,它存储格式的当前状态。
在您的实现中,hex
是标志 0x800
。其他flags会表示是否处于科学计数模式,boolalpha
是否开启等
std::hex
函数在 fmtflags
中设置 std::ios_base::hex
标志。
因此您的输出是此标志的整数值(自您之前发送 std::hex
以来为十六进制)。
std::hex
是一个特殊对象,当使用 operator<<
、
sets the basefield of the stream
str
to hex as if by callingstr.setf(std::ios_base::hex, std::ios_base::base field)
std::ios::hex
(又名 std::ios_base::hex
)是传递给 setf
方法的实际位掩码值。它的值是实现定义的,在你的情况下它似乎是 0x800
。
std::hex
是一个 操纵器,即它是一个具有特定签名的函数:
std::ios_base& hex(std::ios_base& stream) {
stream.setf(std::ios_base::hex, std::ios_base::basefield);
return stream;
}
为流处理操纵器定义了一些特殊的输出运算符。对于对 std::ios_base
的引用进行操作的版本有(忽略运算符实际上是一个函数模板):
std::ostream& operator<< (std::ostream& out, std::ios_base&(*manip)(std::ios_base&));
当与流一起使用时,将调用操纵器函数并设置特定格式标志,在本例中为 std::ios_base::hex
(这就是 std::ios::hex
的实际定义方式)。由于 std::ios_base::hex
是一组标志的成员(其他是 std::ios_base::dec
和 std::ios_base::oct
)设置它还需要清除组中任何潜在的其他标志。因此,使用掩码 (std::ios_base::basefield
) 调用 setf()
以清除任何其他可能设置的标志。
格式标志 std::ios_base::fmtflags
是位掩码类型。值 std::ios_base::hex
是值之一。格式化时你会得到一些数字,很可能是 2 的幂(但是,它不一定是 2 的幂)。您看到的值只是使用十六进制表示法打印的 0x800
(即 2048):设置任何格式标志(width()
除外)是 sticky,即,它们会一直保留到标志被取消设置为止。如果您想查看值 2048(对于您正在使用的实现),您可以使用
std::cout << std::dec << std::ios_base::hex << "\n"; // 2048
std::cout << std::hex << std::ios_base::hex << "\n"; // 800
std::cout << std::showbase << std::ios_base::hex << "\n"; // 0x800
最后一行设置标志 showbase
表示整数值的基数,前缀为:
- 无前缀 => 十进制
- 前导
0x
=> 十六进制 - 前导
0
(但没有x
)=>八进制