C++ 为什么std::(i)ostream将有符号/无符号字符视为文本而不是整数?

C++ 为什么std::(i)ostream将有符号/无符号字符视为文本而不是整数?,c++,language-lawyer,C++,Language Lawyer,此代码不执行它应该执行的操作: #include <iostream> #include <cstdint> int main() { uint8_t small_integer; std::cin >> small_integer; std::cout << small_integer; } 标准(n3797)中对运算符使用了类似的代码,并将其转换为char,如下所示: 27.7.2.2.3基本istream::ope

此代码不执行它应该执行的操作:

#include <iostream>
#include <cstdint>

int main()
{
    uint8_t small_integer;
    std::cin >> small_integer;
    std::cout << small_integer;
}
标准(n3797)中对
运算符使用了类似的代码,并将其转换为
char
,如下所示:

27.7.2.2.3基本istream::operator>>

模板
基本流和操作员>>(基本流和输入、图表和c);
模板
基本流和运算符>>(基本流和输入,无符号字符和c);
模板
基本流和运算符>>(基本流和输入,签名字符和c);
12效果:其行为类似于中的格式化输入成员(如27.7.2.2.1所述)。构建哨兵对象后,将从中提取字符(如果有),并存储在c中。否则,该函数将调用.setstate(failbit)

27.7.3.6.4字符插入器功能模板

//专门化
模板
基本团队和运营商
  • 这是标准要求的行为吗?如果是,则:
  • 你已经回答了。是的,该标准定义了iostreams应该如何处理有符号和无符号字符

  • 这种违反直觉的语义背后的基本原理是什么
  • 因为
    signed char
    unsigned char
    是字符类型,所以iostreams类总是将它们视为字符

    线索在名称中:
    signed char
    是一种有符号字符类型
    unsigned char
    是一种无符号字符类型。其他整数类型的名称中有
    int
    (即使有时是可选的,例如
    short
    long unsigned
    分别与
    short int
    long unsigned int
    相同)

    标准不需要说明为什么这是真的,因为它不是一个设计文档或者是C和C++历史的一个基本原理,它是一个规范。 如果希望类型的行为类似于只有8位的整数,则需要创建自己的类型(例如,使用枚举类型或包含值的结构),并定义相关的运算符重载

  • 这是否应该被视为一个缺陷,是否有人建议改变这种语义

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

    这很烦人。我使用了自己的to_string函数,该函数将(u)int8_t视为整数,而将char视为字符。我为uint8\u t、int8\u t和char添加了单独的专门化,因为我假设这对于不是三种不同类型的人来说是完全有效的。这不是对你问题的回答,而是为了克服这个问题而提出的。@Praetorian,虽然这确实是一个有趣的建议,它解决了一个完全不同的问题。@Matt我假设编译器不能将
    int8_t
    char
    作为参数列表中的类型进行区分。您的
    to_string
    是否真的按照您的意愿工作?如果
    int8_t
    uint8_t
    char
    的typedef,它就不能工作,但如果它们是
    有符号字符和
    无符号字符的typedef,它就可以工作。
    
    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);
        }
    
    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);
    
    // 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);