这段代码没有做它应该做的事情:
#include <iostream>
#include <cstdint>
int main()
{
uint8_t small_integer;
std::cin >> small_integer;
std::cout << small_integer;
}
原因很简单:uint8_t
是 unsigned char
的 typedef,流将此类型视为文本:
视觉C++ 2015 实施
template<class _Traits> inline
basic_istream<char, _Traits>& operator>>(
basic_istream<char, _Traits>& _Istr, unsigned char& _Ch)
{ // extract an unsigned char
return (_Istr >> (char&)_Ch);
}
以及一个类似的代码,用于operator <<
的 cast to char
.
我的问题:
- 标准是否需要此行为(流式处理运算符将有符号/无符号字符视为字符类型而不是整数)?如果是,则:
- 这种违反直觉的语义背后的理由是什么?
- 这是否应被视为缺陷,是否有更改此语义的建议?
我可能应该补充一点解释,为什么我认为这是违反直觉的。尽管类型名称包含单词 char,但 signed
或 unsigned
部分指定特定的整数语义,这些类型通常用作字节大小的整数。甚至标准也通过它们定义了int8_t
/uint8_t
。
UPD:问题是关于unsigned char
和signed char
的流运营商重载的行为。
标准 (n3797) 如下所述:
27.7.2.2.3 basic_istream::运算符>>
template<class charT, class traits>
basic_istream<charT,traits>& operator>>(basic_istream<charT,traits>& in, charT& c);
template<class traits>
basic_istream<char,traits>& operator>>(basic_istream<char,traits>& in, unsigned char& c);
template<class traits>
basic_istream<char,traits>& operator>>(basic_istream<char,traits>& in, signed char& c);
12 效果:行为类似于 in 的格式化输入成员(如 27.7.2.2.1 中所述)。构造哨兵对象后,将从 in 中提取一个字符(如果有),并将其存储在 c 中。否则,函数将调用 in.setstate(failbit)。
27.7.3.6.4 字符插入器功能模板
// 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);
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, unsigned char c);
1效果:表现为输出的格式化输出函数 ( 27.7.3.6.1)。构造字符序列序列。如果 c 具有类型 char 并且流的字符类型不是 char,则 seq 由 out.widen(c) 组成;否则 seq 由 c 组成。确定 seq 的填充,如 27.7.3.6.1 中所述。将顺序插入到输出中。调用 os.width(0)。
所以第一个问题的答案:是的,标准要求operator >>
和operator <<
的行为完全相同 char
、 unsigned char
和 signed char
,即它们读取/写入单个字符,而不是整数。不幸的是,标准没有解释原因。我希望有人能阐明 2 和 3。
- 标准是否要求此行为?如果是,则:
你已经回答了这个问题。是的,该标准定义了 iostream 应如何处理有符号和无符号字符。
- 这种违反直觉的语义背后的理由是什么?
因为signed char
和unsigned char
是字符类型,所以它们总是被iostreams类视为字符。
线索在名称中:signed char
是有符号的字符类型。 unsigned char
是无符号字符类型。 其他整型在其名称中具有int
(即使有时是可选的,例如 short
和 long unsigned
分别与 short int
和 long unsigned int
相同)。
标准不需要说明为什么这是真的,因为它不是设计文档或 C 和 C++ 历史的基本原理,而是一个规范。
如果你想要一个行为类似于只有 8 位的整数的类型,那么你需要创建自己的类型(例如,使用枚举类型或保存值的结构)并定义相关的运算符重载。
- 这是否应被视为缺陷,是否有更改此语义的建议?
不,我不这么认为。它们一直是字符类型,更改它会导致太多代码。