uint8_t can't be printed with cout

114,737

Solution 1

It doesn't really print a blank, but most probably the ASCII character with value 5, which is non-printable (or invisible). There's a number of invisible ASCII character codes, most of them below value 32, which is the blank actually.

You have to convert aa to unsigned int to output the numeric value, since ostream& operator<<(ostream&, unsigned char) tries to output the visible character value.

uint8_t aa=5;

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

Solution 2

Adding a unary + operator before the variable of any primitive data type will give printable numerical value instead of ASCII character(in case of char type).

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

Solution 3

uint8_t will most likely be a typedef for unsigned char. The ostream class has a special overload for unsigned char, i.e. it prints the character with the number 5, which is non-printable, hence the empty space.

Solution 4

  • Making use of ADL (Argument-dependent name lookup):

    #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;
        }
    }
    

    output:

    *
    42
    
  • A custom stream manipulator would also be possible.

  • The unary plus operator is a neat idiom too (cout << +i << endl).

Solution 5

It's because the output operator treats the uint8_t like a char (uint8_t is usually just an alias for unsigned char), so it prints the character with the ASCII code (which is the most common character encoding system) 5.

See e.g. this reference.

Share:
114,737

Related videos on Youtube

CoderInNetwork
Author by

CoderInNetwork

Updated on July 08, 2022

Comments

  • CoderInNetwork
    CoderInNetwork almost 2 years

    I have a weird problem about working with integers in C++.

    I wrote a simple program that sets a value to a variable and then prints it, but it is not working as expected.

    My program has only two lines of code:

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

    The output of this program is value is

    I.e., it prints blank for aa.

    When I change uint8_t to uint16_t the above code works like a charm.

    I use Ubuntu 12.04 (Precise Pangolin), 64-bit, and my compiler version is:

    gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
    
  • Tim Seguine
    Tim Seguine over 10 years
    Since C style casts are frowned upon, wouldn't it be better to do a static_cast?
  • Pete Becker
    Pete Becker over 10 years
    It should be converted to int. A cast is one way to do that, but not the only way. +aa also works.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    @PeteBecker Like this: int(aa) ?
  • Pete Becker
    Pete Becker over 10 years
    That, too; it's a function-style cast.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    @rubenvb I left it to the function style cast, which seems to give the best balance for intuitive reading and loquacious code. Personally I don't have a problem to use simply C-style casts for such a situation.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    Isn't KISS still a valid paradigm??
  • oblitum
    oblitum over 10 years
    @πάνταῥεῖ of course, but don't forget: Everything Should Be Made as Simple as Possible, But Not Simpler
  • oblitum
    oblitum over 10 years
    @πάνταῥεῖ anyway, this is here just to provide an option, one can choose to just include a header for that and then add a using statement once, or opt to cast all over the place where it's needed.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    Another option, yeah! But: The block wise using namespace statements, etc. look really clumsy vs. a pragmatic version simply casting the (unsigned) char values to int for output.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    LOC or different metrics might be valued in the eye of your stakeholder I think ;) ... You'll need to instrument all of your code with these statements you show, instead of just fix a small part using the int() cast!!
  • oblitum
    oblitum over 10 years
    @πάνταῥεῖ of course, but, for me at last, LOC argument doesn't count in favor of casting all over the place when it's the case. One would use such a tool when, precisely, there's a case of several casts and it gets daunting to apply so many of them.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    I don't believe that's really feasible for writing production ready code productively. My co-workers would kill me for proposing such solution in case of question!
  • oblitum
    oblitum over 10 years
    @πάνταῥεῖ ok, keep doing tons of c style casts in c++ code then, anyone is free to be productive the way it is, in the environment that he/she fits the most.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    The problem with your solution is, that you'll really need to open a scoped code block and put the using special_namespace statement to enclose each and every access to the right operator<<() function implementation. Putting a global using special_namespace; won't cover all cases reasonably transparent, but ask for namespace collisions.
  • oblitum
    oblitum over 10 years
    @πάνταῥεῖ seriously? functional style cast, also, is just c style casting. changing one from the other doesn't help in anything in leaving the realm of C, check: stackoverflow.com/a/4775807/1000282. pete-becker commented this on your answer too, but you seem to have missed his last comment.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
  • paulm
    paulm over 10 years
    isn't int(var) and (int)var actually the same thing?
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    @paulm No. c-style casts are discouraged for c++ for a number of reasons.
  • paulm
    paulm over 10 years
    so then what is int(var) doing vs (int)var?
  • paulm
    paulm over 10 years
    stackoverflow.com/questions/1652396/… looks like you still have a C cast here...
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    @paulm (int)var lets you just cast (away) anything, without letting the compiler know about you doing illegal or silly thngs.
  • paulm
    paulm over 10 years
    See the linked question using type(var) is the same as (type)var its the same as the C cast - try it out with const etc, it removes it!
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    @paulm 'looks like you still have a C cast here' No. I read it, it's just if int(var) is valid the effect is the same. It's not the main topic of this Q/A though.
  • paulm
    paulm over 10 years
    Exactly, so why bother replacing the C cast when static_cast is safer as it won't also apply const_cast or the effects of reinterpret_cast?
  • πάντα ῥεῖ
    πάντα ῥεῖ over 10 years
    @paulm static_cast<int>(var) would be perfectly OK for me (as I mentioned), it just looks ridiculous(ly long to type) for others ...
  • Admin
    Admin over 9 years
    The response "No. c-style casts are discouraged for c++ for a number of reasons." to "isn't int(var) and (int)var actually the same thing?" sure makes it seem as if you didn't realise int(var) and (int)var have exactly the same meaning. int(var) is discouraged in exactly those cases where (int)var is, for exactly the same reasons, because it means exactly the same thing. (I can understand why you'd go for it here anyway, though, so I'm not saying you need to use static_cast. I just think the comment trail here got a bit unnecessarily confusing.)
  • πάντα ῥεῖ
    πάντα ῥεῖ over 9 years
    @hvd Of course I was aware that this is exactly the same. It was just a stupid discussion what the correct (and shortest) cast style should be.
  • antred
    antred almost 9 years
    I wish the standard really treated std::uint8_t as a separate type and not just a friggin' typedef. There is no sane reason to apply character-semantics to these types when used in conjunction with stream objects.
  • jww
    jww over 7 years
    @PeteBecker - Please forgive my ignorance.... What is +aa called (from your statement "+aa also works").
  • Pete Becker
    Pete Becker over 7 years
    @jww - it's a unary plus. Just like unary minus (-aa), except that it doesn't affect the value. But it promotes smaller types to int, as do all arithmetic operators. (and there's nothing to forgive; it's rather obscure)
  • Dmytro
    Dmytro over 7 years
    unsigned(x)... looks like i should start collecting a list of non obvious subtleties in C/C++ that are likely to blow the minds of those who never seen them before.
  • πάντα ῥεῖ
    πάντα ῥεῖ over 7 years
    @DouglasDaseeco How so? It's pretty clear what happens.
  • Georges
    Georges almost 7 years
    This solution is very elegant & effective, because it works with templates. In facts, that's the only solution I've spotted that works for me. One caveat though, the first function has a bug, because 'os' is bound to a single type, and therefore, either the signed or the unsigned value will be sent to the wrong version of operator<<(). The fix is simple enough: return std::is_signed<char>::value ? os << static_cast<int>(c) : os << static_cast<unsigned int>(c);
  • oblitum
    oblitum almost 7 years
    @GeorgesBerenger correct!, indeed I missed that ternary result. Glad you liked, it seems love or hate :)
  • Super-intelligent Shade
    Super-intelligent Shade over 6 years
    Nice solution. However, you probably want to do something similar for std::istream to avoid any surprises with reading from an input stream
  • TUNAPRO1234
    TUNAPRO1234 over 6 years
    Agree with @GeorgesBerenger: This is the only means by which a template type, which may be char or unsigned char (int8_t or uint8_t), will work properly. And it was the solution I was looking for. Thank you.
  • Eljay
    Eljay over 5 years
    The +aa style is idiomatic in JavaScript (which does something different). I don't see the unary + used much in C++, even in this "apply the usual arithmetic promotion", which in this situation is an appropriate and suitable use-case.
  • Calmarius
    Calmarius about 5 years
    +aa style is the best when you work with templated code that needs to handle number from uint8_t to uint64_t.
  • R1S8K
    R1S8K about 5 years
    That's nice, but why doesn't c++ treat uint8_t as unsigned char which would be numerical values?
  • R1S8K
    R1S8K about 5 years
    Why? the C compiler treats it as a number. I think C++ is different at this point.
  • Some programmer dude
    Some programmer dude about 5 years
    @PerchEagle If you read the linked reference you will see that the operator is overloaded for both signed and unsigned characters (beyond plain char which in C++ is really a third separate type). So if uint8_t is an alias for unsigned char (very likely) that's what will be used.
  • R1S8K
    R1S8K about 5 years
    Could you check my answer on this thread and tell me if my answer is right or not? stackoverflow.com/questions/15585267/…, my answer is before the last one. Thank you so much.
  • Harsh
    Harsh about 4 years
    @R1S8K this is because while uint8_t is just a type def of unsigned char, unsigned char itself is handled by ostream just like char and prints its ASCII value.
  • R1S8K
    R1S8K about 4 years
    @Harsh Thanks man ! so it's a type def of unsigned char that explains a lot. So the only integer is int, right ?
  • Harsh
    Harsh about 4 years
    @R1S8K Well, the smallest integer type would be short int which takes up 2 bytes. There are a few other variations of the integer type as well.
  • R1S8K
    R1S8K about 4 years
    @Harsh Also I think when programming and declaring variables, it doesn't matter if I declare a variable that would deal only with small numbers not exceeding like 250 with a big register size like long or int because the compiler would optimize the use of RAM or flash according to what fills that register, am I right ?
  • Harsh
    Harsh about 4 years
    @R1S8K Hmm... I am not sure; but I am strongly inclined towards that not being the case. :)
  • R1S8K
    R1S8K about 4 years
    @Harsh Yes you're right, I did a small test in Arduino IDE, and declared a variable long and initialize it with a small number, big number and nothing, it's all the same and nothing has been taken from the RAM/Flash !! But I didn't write any code beside setup and loop functions, I think there has to be some code using the variables to be counted from the RAM or the flash if it's assigned with something like const dataType variableName[] PROGMEM = {data0, data1, data3…​};
  • Tony Delroy
    Tony Delroy over 3 years
    "Making use of ADL (Argument-dependent name lookup):" - not that it's otherwise important, but ADL is not utilised by this answer... the operator<< overloads are found using normal namespace searching if and only if that using namespace numerical_chars; has been explicitly specified. ADL is relevant when one of the function/operator argument types is in the same namespace as the function/operator - in your code, std::ostream is not in numerical_chars, and the char types aren't either of course.
  • David Ljung Madison Stellar
    David Ljung Madison Stellar over 3 years
    @R1S8K - just because you init a variable to a small number doesn't mean it will stay that way. It's very unlikely that the compiler can determine all possible values a variable will hold for a given program (and that they fit in a smaller size than you declared), so I'd be surprised if they actually optimized this, except possibly in cases where a variable was never set and such.
  • R1S8K
    R1S8K over 3 years
    @DavidLjungMadisonStellar Yes, I think the point would be if the variable hasn't been set, and probably the compiler won't optimize the variable to fit the value because that variable could change to any value during operation time so the variable size is as is.
  • David Ljung Madison Stellar
    David Ljung Madison Stellar over 3 years
    @R1S8K exactly. And you can fundamentally prove that it's impossible to know (for a general purpose program) all the possible values all variables will hold (and hence their size). That's why (static) lanaguages that are concerned about memory usage give you different sized integers. Dynamic languages can resize for you on the fly.
  • Sadegh
    Sadegh about 3 years
    variable size will increase to 4 byte from 1 byte. I want a 1 byte variable. any help?
  • Sadegh
    Sadegh about 3 years
    @PeteBecker variable size will increase to 4 byte from 1 byte. I want a 1 byte variable. any help?
  • Sadegh
    Sadegh about 3 years
    variable size will increase to 4 byte from 1 byte. I want a 1 byte variable. any help?
  • πάντα ῥεῖ
    πάντα ῥεῖ about 3 years
    @Sadegh The cast doesn't involve any "variables", just register operations, which won't affect your stack or otherwise memory management.
  • steph643
    steph643 over 2 years
    This seems to be the only solution that properly outputs a 2-digit hexa: uint8_t c = 33; os << "0x" << std::hex << c; All other solutions add extra digits.
  • trexxet
    trexxet about 2 years
    Ingenious, I have a templated << operator for uint8_t and float, and this one works perfectly
  • Matt Messersmith
    Matt Messersmith about 2 years
    Aren't we arguing about the wrong thing? This shouldn't even need to be casted (intuitively). An unsigned int shouldn't be printed as an ASCII character by default...I'm curious if the reason for this is just "C heritage", or if there's a different/deeper reason?
  • πάντα ῥεῖ
    πάντα ῥεῖ about 2 years
    @MattMessersmith it's not unsigned int in question here.