uint8_t不能用 cout 打印

uint8_t can't be printed with cout

提问人:CoderInNetwork 提问时间:10/24/2013 最后编辑:Jan SchultkeCoderInNetwork 更新时间:9/5/2023 访问量:148564

问:

我编写了一个简单的程序,将值设置为变量,然后打印它,但它没有按预期工作。我的程序只有两行代码:

uint8_t a = 5;

cout << "value is " << a << endl;

该程序的输出是 ,即它为 打印空白。value is a

当我更改为 时,上面的代码就像一个魅力。uint8_tuint16_t

我使用 Ubuntu 12.04 (Precise Pangolin),64 位,我的编译器版本是:

gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
C++ cout unsigned-char uint8t c++-常见问题解答

评论

3赞 phuclv 4/30/2017
iostream 行为uint8_t可能重复
0赞 phuclv 9/3/2018
cout 不打印无符号字符
2赞 Matt Messersmith 4/10/2022
你真的会认为这会“行得通”。RIP C++ 类型系统。这难道不是类型的重点吗?

答:

233赞 πάντα ῥεῖ 10/24/2013 #1

它并没有真正打印空白,但很可能是值为 5 的 ASCII 字符,该字符是不可打印(或不可见)的。有许多不可见的 ASCII 字符代码,其中大多数低于值 32,这实际上是空白。

您必须转换为才能输出数值,因为尝试输出可见字符值。aunsigned intostream& operator<<(ostream&, unsigned char)

uint8_t a = 5;

cout << "value is " << unsigned(a) << endl;

评论

30赞 Tim Seguine 10/24/2013
既然 C 风格的演员不受欢迎,那么做一个static_cast不是更好吗?
48赞 Pete Becker 10/24/2013
它应转换为 .演员表是实现这一目标的一种方式,但不是唯一的方法。 也有效。int+aa
7赞 paulm 2/18/2014
int(var) 和 (int)var 实际上不是一回事吗?
9赞 paulm 2/18/2014
使用 type(var) 查看链接的问题与 (type)var 相同,它与 C 强制转换相同 - 尝试使用 const 等,它会删除它!
16赞 2/26/2015
对“int(var)和(int)var实际上不是一回事吗?”的回答“不,c-style casts are discourage for c++ due of number of reasons”,这确实让人觉得你没有意识到,并且具有完全相同的含义。 出于完全相同的原因,在那些 is 的情况下不鼓励这样做,因为它意味着完全相同的事情。(不过,我能理解你为什么要在这里使用它,所以我并不是说你需要使用 .我只是觉得这里的评论线索有点不必要地令人困惑。int(var)(int)varint(var)(int)varstatic_cast
61赞 arne 10/24/2013 #2

uint8_t很可能是 for .该类有一个特殊的重载 ,即它打印带有数字 5 的字符,这是不可打印的,因此是空白的。typedefunsigned charostreamunsigned char

评论

35赞 antred 7/31/2015
我希望标准真的将 std::uint8_t 视为一个单独的类型,而不仅仅是一个 friggin' typedef。当与流对象结合使用时,没有理由将字符语义应用于这些类型。
20赞 Some programmer dude 10/24/2013 #3

这是因为输出运算符将 a 视为 (通常只是 的别名),因此它使用 ASCII 代码(这是最常见的字符编码系统)打印字符。uint8_tcharuint8_tunsigned char5

例如,请参阅此参考资料

评论

0赞 R1S8K 5/26/2019
为什么?C 编译器将其视为数字。我认为 C++ 在这一点上是不同的。
0赞 Some programmer dude 5/26/2019
@PerchEagle 如果您阅读链接的引用,您将看到 和 字符的运算符都重载了(除了普通字符之外,C++实际上是第三种单独的类型)。因此,如果是(很可能)的别名,则将使用该别名。signedunsignedcharuint8_tunsigned char
0赞 R1S8K 5/26/2019
你能检查我在这个线程上的答案并告诉我我的答案是否正确吗?stackoverflow.com/questions/15585267/...,我的答案是在最后一个之前。非常感谢。
8赞 0xF1 10/24/2013 #4

cout被视为 ASCII 值,这是一个不可打印的字符,请在打印前尝试排版。aachar5int

评论

0赞 Sadegh J 5/26/2021
变量大小将从 1 个字节增加到 4 个字节。我想要一个 1 字节的变量。有什么帮助吗?
21赞 oblitum 1/28/2014 #5
  • 利用 ADL(与参数相关的名称查找):

    #include <cstdint>
    #include <iostream>
    #include <typeinfo>
    
    namespace numerical_chars {
    inline std::ostream &operator<<(std::ostream &os, char c) {
        return std::is_signed<char>::value ? os << static_cast<int>(c)
                                           : os << static_cast<unsigned int>(c);
    }
    
    inline std::ostream &operator<<(std::ostream &os, signed char c) {
        return os << static_cast<int>(c);
    }
    
    inline std::ostream &operator<<(std::ostream &os, unsigned char c) {
        return os << static_cast<unsigned int>(c);
    }
    }
    
    int main() {
        using namespace std;
    
        uint8_t i = 42;
    
        {
            cout << i << endl;
        }
    
        {
            using namespace numerical_chars;
            cout << i << endl;
        }
    }
    

    输出:

    *
    42
    
  • 自定义流操纵器也是可能的。

  • 一元加号运算符也是一个简洁的成语()。cout << +i << endl

评论

9赞 πάντα ῥεῖ 1/30/2014
KISS不仍然是一个有效的范式吗??
1赞 oblitum 1/30/2014
@πάνταῥεῖ当然,但别忘了:一切都应该尽可能简单,但不能更简单
4赞 oblitum 1/30/2014
@πάνταῥεῖ好吧,继续在 C++ 代码中进行大量的 C 风格转换,那么任何人都可以在他/她最适合的环境中自由地以现在的方式提高工作效率。
5赞 oblitum 1/30/2014
@πάνταῥεῖ认真的?功能风格铸造,也只是C风格铸造。从另一个改变一个对离开 C 领域没有任何帮助,检查:stackoverflow.com/a/4775807/1000282。皮特-贝克尔也对你的回答发表了评论,但你似乎错过了他的最后一条评论。
6赞 Georges 6/25/2017
这个解决方案非常优雅和有效,因为它适用于模板。事实上,这是我发现的唯一适合我的解决方案。但需要注意的是,第一个函数有一个错误,因为“os”绑定到单个类型,因此,有符号或无符号值将被发送到错误版本的 operator<<()。修复方法很简单:return std::is_signed<char>::value ? os << static_cast<int>(c) : os << static_cast<unsigned int>(c);
3赞 Sergey 6/29/2015 #6

正如其他人之前所说,之所以会出现问题,是因为标准流将有符号字符和无符号字符视为单个字符,而不是数字。

这是我的解决方案,代码更改最少:

uint8_t aa = 5;

cout << "value is " << aa + 0 << endl;

任何数字(包括浮点数)的加法都是安全的。"+0"

对于整数类型,它会将结果类型更改为 if 。如果 .intsizeof(aa) < sizeof(int)sizeof(aa) >= sizeof(int)

此解决方案也适用于准备打印以流式传输,而其他一些解决方案则不太好:int8_t

int8_t aa = -120;

cout << "value is " << aa + 0 << endl;
cout << "bad value is " << unsigned(aa) << endl;

输出:

value is -120
bad value is 4294967176

P.S. pepper_chico 和 πάντα ῥεῖ 给出的 ADL 解决方案真的很漂亮。

评论

0赞 Sadegh J 5/26/2021
变量大小将从 1 个字节增加到 4 个字节。我想要一个 1 字节的变量。有什么帮助吗?
0赞 trexxet 3/27/2022
巧妙的是,我有一个用于uint8_t和浮点的模板化<<运算符,这个运算符效果很好
79赞 SridharKritha 8/13/2015 #7

在任何基元数据类型的变量之前添加一元 + 运算符将产生可打印的数值,而不是 ASCII 字符(如果是 char 类型)。

uint8_t a = 5;
cout << "value is " << +a << endl; // value is 5

这之所以有效,是因为结果被提升为 int+aa

评论

2赞 R1S8K 5/26/2019
这很好,但为什么 c++ 不被视为数值呢?uint8_tunsigned char
1赞 Harsh 5/16/2020
@R1S8K这是因为 while 只是 def 的一个类型,它本身由 just like 处理并打印其 ASCII 值。uint8_tunsigned charunsigned charostreamchar
0赞 R1S8K 5/17/2020
@Harsh 谢谢伙计!所以它是一种类型 def 可以解释很多。所以唯一的整数是 ,对吧?unsigned charint
0赞 Harsh 5/18/2020
@R1S8K 嗯,最小的整数类型是占用 2 个字节。整数类型还有其他一些变体。short int
0赞 R1S8K 5/19/2020
@Harsh 此外,我认为在编程和声明变量时,如果我声明一个变量,该变量只能处理不超过 250 的小数字,并且寄存器大小很大,或者因为编译器会根据填充该寄存器的内容优化 RAM 或闪存的使用,我说得对吗?longint
6赞 R Sahu 11/18/2015 #8

和之间的重载是非成员函数。可以显式使用 member 函数将 (或 ) 视为 .operator<<()std::ostreamcharcharuint8_tint

#include <iostream>
#include <cstddef>

int main()
{
   uint8_t aa=5;

   std::cout << "value is ";
   std::cout.operator<<(aa);
   std::cout << std::endl;

   return 0;
}

输出:

value is 5
1赞 vitaut 12/11/2023 #9

这是 iostream 的已知问题之一,iostream 将 (通常是 的别名 ) 解释为代码单元而不是整数类型。它已在 C++20 std::格式中修复。例如 (godbolt):unsigned charuint8_tunsigned char

uint8_t a = 5;
std::cout << std::format("value is {}\n", a);

指纹

value is 5

在 C++23 中,这可以进一步简化为:

uint8_t a = 5;
std::print("value is {}\n", a);

免责声明:我是 C++20 和 C++23 的作者。std::formatstd::print