217

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 a = 5;

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

The output of this program is value is , i.e., it prints blank for a.

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)
Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
CoderInNetwork
  • 2,923
  • 4
  • 22
  • 39

8 Answers8

230

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;
jww
  • 97,681
  • 90
  • 411
  • 885
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 30
    Since C style casts are frowned upon, wouldn't it be better to do a static_cast? – Tim Seguine Oct 24 '13 at 12:09
  • 47
    It should be **converted** to `int`. A cast is one way to do that, but not the only way. `+aa` also works. – Pete Becker Oct 24 '13 at 14:07
  • @PeteBecker Like this: int(aa) ? – πάντα ῥεῖ Oct 24 '13 at 14:50
  • 3
    That, too; it's a function-style cast. – Pete Becker Oct 24 '13 at 14:53
  • @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. – πάντα ῥεῖ Oct 24 '13 at 18:18
  • 7
    isn't int(var) and (int)var actually the same thing? – paulm Feb 17 '14 at 23:18
  • 1
    @paulm No. c-style casts are discouraged for c++ for a number of reasons. – πάντα ῥεῖ Feb 17 '14 at 23:20
  • 1
    so then what is int(var) doing vs (int)var? – paulm Feb 17 '14 at 23:20
  • 2
    http://stackoverflow.com/questions/1652396/what-is-the-difference-between-typevalue-and-typevalue looks like you still have a C cast here... – paulm Feb 17 '14 at 23:21
  • 2
    @paulm `(int)var` lets you just cast (away) anything, without letting the compiler know about you doing illegal or silly thngs. – πάντα ῥεῖ Feb 17 '14 at 23:24
  • 9
    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! – paulm Feb 17 '14 at 23:27
  • @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. – πάντα ῥεῖ Feb 17 '14 at 23:29
  • 3
    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? – paulm Feb 17 '14 at 23:31
  • 3
    @paulm `static_cast(var)` would be perfectly OK for me (as I mentioned), it just looks ridiculous(ly long to type) for others ... – πάντα ῥεῖ Feb 17 '14 at 23:35
  • 16
    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.) –  Feb 25 '15 at 16:01
  • 1
    @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. – πάντα ῥεῖ Feb 25 '15 at 16:03
  • @PeteBecker - Please forgive my ignorance.... What is *`+aa`* called (from your statement *"+aa also works"*). – jww Oct 20 '16 at 09:35
  • 5
    @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) – Pete Becker Oct 20 '16 at 15:57
  • 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. – Dmytro Dec 07 '16 at 19:19
  • @DouglasDaseeco How so? It's pretty clear what happens. – πάντα ῥεῖ Feb 14 '17 at 20:58
  • 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. – Eljay Sep 17 '18 at 13:01
  • 2
    `+aa` style is the best when you work with templated code that needs to handle number from uint8_t to uint64_t. – Calmarius Apr 01 '19 at 13:31
  • @PeteBecker variable size will increase to 4 byte from 1 byte. I want a 1 byte variable. any help? – Sadegh J May 26 '21 at 14:08
  • @Sadegh The cast doesn't involve any _"variables"_, just register operations, which won't affect your stack or otherwise memory management. – πάντα ῥεῖ May 26 '21 at 15:07
  • 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? – Matt Messersmith Apr 09 '22 at 18:01
  • @MattMessersmith it's not `unsigned int` in question here. – πάντα ῥεῖ Apr 09 '22 at 18:08
74

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

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

This works because +a result in a being promoted to int.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
SridharKritha
  • 8,481
  • 2
  • 52
  • 43
  • 1
    That's nice, but why doesn't c++ treat `uint8_t` as `unsigned char` which would be numerical values? – R1S8K May 25 '19 at 21:35
  • 1
    @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. – Harsh May 16 '20 at 08:55
  • @Harsh Thanks man ! so it's a type def of `unsigned char` that explains a lot. So the only integer is `int`, right ? – R1S8K May 17 '20 at 15:03
  • @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. – Harsh May 17 '20 at 17:09
  • @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 ? – R1S8K May 19 '20 at 08:58
  • @R1S8K Hmm... I am not sure; but I am strongly inclined towards that not being the case. :) – Harsh May 19 '20 at 14:05
  • @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…​};` – R1S8K May 20 '20 at 00:13
  • @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. – David Ljung Madison Stellar Oct 26 '20 at 21:12
  • @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. – R1S8K Nov 30 '20 at 13:38
  • @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. – David Ljung Madison Stellar Dec 01 '20 at 00:09
  • How does this work? – WeZZard Jan 04 '23 at 15:47
  • This solution should be up-voted more because it is much more flexible than casting to (int) as is suggested in the other solution. The reason is simple: casting for fixed type (int) works well when you know for sure that the type that you are trying to output is int8_t. However, when you write a template class or function, you do not know the type upfront and casting to fixed type like (int) can lead to undesired behavior if the template user instantiates it with an integer type larger than int (for example with int64_t). Adding unary + does not have this issue. – Regus Pregus May 31 '23 at 16:08
61

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.

arne
  • 4,514
  • 1
  • 28
  • 47
  • 33
    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. – antred Jul 31 '15 at 14:19
21
  • 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).
oblitum
  • 11,380
  • 6
  • 54
  • 120
  • 9
    Isn't [KISS](http://en.wikipedia.org/wiki/KISS_principle) still a valid paradigm?? – πάντα ῥεῖ Jan 30 '14 at 00:58
  • 1
    @πάνταῥεῖ of course, but don't forget: [Everything Should Be Made as Simple as Possible, But Not Simpler](http://quoteinvestigator.com/2011/05/13/einstein-simple/) – oblitum Jan 30 '14 at 01:22
  • 1
    @πάνταῥεῖ 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. – oblitum Jan 30 '14 at 01:26
  • 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. – πάντα ῥεῖ Jan 30 '14 at 01:30
  • 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!! – πάντα ῥεῖ Jan 30 '14 at 01:33
  • 1
    @πάνταῥεῖ 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. – oblitum Jan 30 '14 at 01:37
  • 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! – πάντα ῥεῖ Jan 30 '14 at 02:04
  • 4
    @πάνταῥεῖ 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. – oblitum Jan 30 '14 at 02:13
  • 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. – πάντα ῥεῖ Jan 30 '14 at 02:24
  • 5
    @πάνταῥεῖ 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: http://stackoverflow.com/a/4775807/1000282. pete-becker commented this on your answer too, but you seem to have missed his last comment. – oblitum Jan 30 '14 at 02:58
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/46392/discussion-between---and-pepper-chico) – πάντα ῥεῖ Jan 30 '14 at 03:05
  • 6
    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::value ? os << static_cast(c) : os << static_cast(c);` – Georges Jun 24 '17 at 21:21
  • 1
    @GeorgesBerenger correct!, indeed I missed that ternary result. Glad you liked, it seems love or hate :) – oblitum Jun 24 '17 at 23:15
  • Nice solution. However, you probably want to do something similar for `std::istream` to avoid any surprises with reading from an input stream – Super-intelligent Shade Sep 25 '17 at 20:18
  • 1
    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. – natersoz Feb 27 '18 at 18:29
  • 1
    *"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. – Tony Delroy Sep 05 '20 at 22:32
  • 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. – steph643 Feb 27 '22 at 13:43
20

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Why? the C compiler treats it as a number. I think C++ is different at this point. – R1S8K May 25 '19 at 21:36
  • @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. – Some programmer dude May 25 '19 at 22:05
  • Could you check my answer on this thread and tell me if my answer is right or not? https://stackoverflow.com/questions/15585267/cout-not-printing-unsigned-char, my answer is before the last one. Thank you so much. – R1S8K May 26 '19 at 12:00
8

cout is treating aa as char of ASCII value 5 which is an unprintable character, try typecasting to int before printing.

0xF1
  • 6,046
  • 2
  • 27
  • 50
7

The operator<<() overload between std::ostream and char is a non-member function. You can explicitly use the member function to treat a char (or a uint8_t) as an int.

#include <iostream>
#include <cstddef>

int main()
{
   uint8_t aa=5;

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

   return 0;
}

Output:

value is 5
R Sahu
  • 204,454
  • 14
  • 159
  • 270
3

As others said before the problem occurs because standard stream treats signed char and unsigned char as single characters and not as numbers.

Here is my solution with minimal code changes:

uint8_t aa = 5;

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

Adding "+0" is safe with any number including floating point.

For integer types it will change type of result to int if sizeof(aa) < sizeof(int). And it will not change type if sizeof(aa) >= sizeof(int).

This solution is also good for preparing int8_t to be printed to stream while some other solutions are not so good:

int8_t aa = -120;

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

Output:

value is -120
bad value is 4294967176

P.S. Solution with ADL given by pepper_chico and πάντα ῥεῖ is really beautiful.

Sergey
  • 1,552
  • 20
  • 18