为什么std::( i)ostream将signed / unsigned char视为文本而不是整数?

时间:2016-04-25 14:34:26

标签: c++ language-lawyer

此代码没有做它应该做的事情:

#include <iostream>
#include <cstdint>

int main()
{
    uint8_t small_integer;
    std::cin >> small_integer;
    std::cout << small_integer;
}

原因很简单:uint8_tunsigned char的typedef,溪流将此类型视为文字:
Visual 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);
    }

char投射到operator <<的类似代码。

我的问题:

  1. 此行为(流操作符将signed / unsigned char视为字符类型而不是整数)是否需要标准? 如果是的话:
    1. 这种违反直觉的语义背后的理由是什么?
    2. 如果这被视为缺陷,是否有建议改变这种语义?
  2. 我应该添加一些解释为什么我认为它违反直觉。 尽管类型名称包含单词char,但signedunsigned部分指定特定的整数语义,并且这些类型通常用作字节大小的整数。甚至标准也通过它们定义int8_t / uint8_t

    UPD:问题是unsigned charsigned char的流媒体运营商重载行为。

2 个答案:

答案 0 :(得分:3)

标准(n3797)说明如下:

  

27.7.2.2.3 basic_istream :: operator&gt;&gt;

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 E ff ects:表现得像in的格式化输入成员(如27.7.2.2.1所述)。构建了一个哨兵对象从中提取一个字符,如果有的话,并存储在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 E ff ects:表现为out的格式化输出函数(27.7.3.6.1)。构造一个字符序列seq。如果c的类型为char且流的字符类型不是char,则 seq由out.widen(c)组成;否则seq由c 组成。确定seq的填充,如27.7.3.6.1中所述。插入seq。调用os.width(0)。

第一个问题的答案是:是的,标准要求operator >>operator <<charunsigned charsigned char的行为完全相同,即他们读/写一个字符,而不是整数。遗憾的是,标准并没有解释原因。我希望有人能够解释2和3。

答案 1 :(得分:1)

  
      
  1. 标准是否需要此行为?如果是的话:
  2.   

你已经回答了这个问题。是的,该标准定义了iostream应如何处理有符号和无符号字符。

  
      
  1. 这种违反直觉的语义背后的理由是什么?
  2.   

由于signed charunsigned char字符类型,因此iostreams类始终将它们视为字符。

线索在名称中:signed char是签名字符类型。 unsigned char是无符号字符类型。其他整数类型的名称中包含int(即使它有时是可选的,例如shortlong unsignedshort intlong unsigned int相同分别地)。

标准并不需要说为什么这是真的,因为它不是设计文档或C和C ++历史的基本原理,它是&#39;规范。

如果你想要一个行为类似于只有8位的整数的类型,那么你需要创建自己的类型(例如使用枚举类型或保存值的结构)并定义相关的运算符重载。 / p>

  
      
  1. 如果这被视为缺陷,是否有建议改变这种语义?
  2.   

不,我不这么认为。它们一直是字符类型,它会破坏太多代码来改变它。