uint8_t无法使用cout打印


146

关于在C ++中使用整数,我有一个奇怪的问题。

我编写了一个简单的程序,该程序将一个值设置为一个变量,然后将其打印出来,但是它没有按预期工作。

我的程序只有两行代码:

uint8_t aa = 5;

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

该程序的输出是 value is

即,它为打印空白aa

当我更改uint8_tuint16_t上面的代码时,它的工作原理很吸引人。

我使用的是64位Ubuntu 12.04(精确的穿山甲),我的编译器版本为:

gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)


Answers:


150

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

由于尝试输出可见字符值,因此必须转换aaunsigned int输出数字ostream& operator<<(ostream&, unsigned char)值。

uint8_t aa=5;

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

24
由于对C样式的转换不满意,因此进行static_cast会更好吗?
Tim Seguine 2013年

37
应该将其转换int。强制转换是实现此目的的一种方法,但不是唯一的方法。+aa也可以。
Pete Becker

5
int(var)和(int)var实际上不是一回事吗?
paulm 2014年

9
看到使用type(var)链接的问题与(type)var 相同,并且与C转换相同 -使用const等进行尝试,它将其删除!
paulm 2014年

13
响应“由于多种原因,不建议使用c ++进行c样式转换。” 到“ int(var)和(int)var实际上不是同一回事吗?” 确保看起来好像您没有意识到int(var)并且(int)var具有完全相同的含义。出于完全相同的原因,int(var)在完全相同的情况下不鼓励使用(int)var因为它表示的是完全相同的事物。(不过,我知道您为什么仍然要在这里使用它,所以我并不是说您需要使用static_cast。我只是认为这里的评论线索有些不必要地令人困惑。)

46

uint8_t将最有可能成为一个typedefunsigned char。所述ostream类具有特殊的过载unsigned char,即,其将打印带5号,这是不可打印的,因此,空的空间的字符。


14
我希望标准真的将std :: uint8_t视为一个单独的类型,而不仅仅是friggin'typedef。与流对象一起使用时,没有理智的理由将字符语义应用于这些类型。
antant

37

在任何原始数据类型的变量之前添加一元+运算符将提供可打印的数字值,而不是ASCII字符(对于char类型)。

uint8_t aa = 5;
cout<<"value is "<< +aa <<endl;

很好,但是c ++为什么不将数字值uint8_t视为unsigned char
R1S8K

@ R1S8K这是因为虽然uint8_t仅仅是的类型def unsigned charunsigned char其本身ostream就像一样处理char并打印其ASCII值。
严厉

@严厉谢谢男人!所以它的类型定义unsigned char可以解释很多。所以唯一的整数是int吧?
R1S8K

@ R1S8K嗯,最小的整数类型将short int占用2个字节。整数类型还有其他一些变体。
严苛

@Harsh另外,我认为在编程和声明变量时,声明是否只处理不超过250的小数字和较大的寄存器大小(例如longint因为编译器会优化RAM或闪存的使用)并不重要根据填写该寄存器的内容,对吗?
R1S8K

16

这是因为输出运算符将uint8_ta 视为charuint8_t通常只是的别名unsigned char),因此它使用ASCII码(这是最常见的字符编码系统)来打印字符5

参见例如该参考文献


为什么?C编译器将其视为数字。我认为C ++在这一点上有所不同。
R1S8K

@PerchEagle如果您阅读链接的参考资料,您会发现操作符的两个字符signedunsigned字符都已重载(超出普通字符char,在C ++中,它实际上是第三种单独的类型)。因此,如果(非常可能)uint8_t使用别名,unsigned char那么将使用该别名。
一位程序员花花公子

您能否检查我在此线程上的答案,并告诉我我的答案是否正确?stackoverflow.com/questions/15585267/…,我的回答在最后一个之前。非常感谢。
R1S8K

14
  • 利用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)。

8
是不是KISS仍然是一个有效的模式?
2014年

1
@πάνταῥεῖ当然,但不要忘记:一切都应该尽可能简单,但不要更简单
pepper_chico 2014年

4
@πάνταῥεῖ好的,然后继续在c ++代码中进行大量的c样式转换,在他/她最适合的环境中,任何人都可以自由地按自己的方式进行生产。
Pepper_chico 2014年

5
@πάνταῥεῖ认真吗?功能样式转换也只是c样式转换。相互更改一个对离开C领域没有任何帮助,请检查:stackoverflow.com/a/4775807/1000282。pete-becker也对您的回答发表了评论,但您似乎错过了他的最后评论。
pepper_chico 2014年

3
该解决方案非常优雅且有效,因为它可与模板一起使用。实际上,这是我发现的唯一对我有效的解决方案。请注意,第一个函数有一个错误,因为'os'绑定到单一类型,因此,有符号或无符号值都将被发送到错误的operator <<()版本。解决方法非常简单:return std::is_signed<char>::value ? os << static_cast<int>(c) : os << static_cast<unsigned int>(c);
Georges

7

cout正在将ASCII值aa视为不可打印的字符,请尝试在打印之前进行类型转换。char5int


4

operator<<()之间的重载是非成员函数。您可以显式使用成员函数将(或)视为。istreamcharcharuint8_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

2

正如其他人在问题发生之前所说的那样,因为标准流将带符号的char和无符号的char视为单个字符而不是数字。

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

uint8_t aa = 5;

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

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

对于整数类型,它将结果类型更改为intif sizeof(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

Pepper_chico和πάνταῥεῖ给出的带有ADL的PS解决方案非常漂亮。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.