uint8_t can't be printed with cout
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.
Related videos on Youtube
CoderInNetwork
Updated on July 08, 2022Comments
-
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
touint16_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)
-
phuclv about 7 yearsPossible duplicate of uint8_t iostream behavior
-
phuclv over 5 years
-
Matt Messersmith about 2 yearsYou'd really think this would "just work". RIP C++ type system. Isn't this the whole point of types?
-
-
Tim Seguine over 10 yearsSince C style casts are frowned upon, wouldn't it be better to do a static_cast?
-
Pete Becker over 10 yearsIt 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 over 10 yearsThat, 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 yearsIsn't KISS still a valid paradigm??
-
oblitum over 10 years@πάνταῥεῖ of course, but don't forget: Everything Should Be Made as Simple as Possible, But Not Simpler
-
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 yearsAnother 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 yearsLOC 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 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 yearsI 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 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 yearsThe 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 rightoperator<<()
function implementation. Putting a globalusing special_namespace;
won't cover all cases reasonably transparent, but ask for namespace collisions. -
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 over 10 yearsisn'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 over 10 yearsso then what is int(var) doing vs (int)var?
-
paulm over 10 yearsstackoverflow.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 over 10 yearsSee 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 over 10 yearsExactly, 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 over 9 yearsThe 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 usestatic_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 almost 9 yearsI 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 over 7 years@PeteBecker - Please forgive my ignorance.... What is
+aa
called (from your statement "+aa also works"). -
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 toint
, as do all arithmetic operators. (and there's nothing to forgive; it's rather obscure) -
Dmytro over 7 yearsunsigned(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 almost 7 yearsThis 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 almost 7 years@GeorgesBerenger correct!, indeed I missed that ternary result. Glad you liked, it seems love or hate :)
-
Super-intelligent Shade over 6 yearsNice solution. However, you probably want to do something similar for
std::istream
to avoid any surprises with reading from an input stream -
TUNAPRO1234 over 6 yearsAgree 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 over 5 yearsThe
+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 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 about 5 yearsThat's nice, but why doesn't c++ treat
uint8_t
asunsigned char
which would be numerical values? -
R1S8K about 5 yearsWhy? the C compiler treats it as a number. I think C++ is different at this point.
-
Some programmer dude about 5 years@PerchEagle If you read the linked reference you will see that the operator is overloaded for both
signed
andunsigned
characters (beyond plainchar
which in C++ is really a third separate type). So ifuint8_t
is an alias forunsigned char
(very likely) that's what will be used. -
R1S8K about 5 yearsCould 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 about 4 years@R1S8K this is because while
uint8_t
is just a type def ofunsigned char
,unsigned char
itself is handled byostream
just likechar
and prints its ASCII value. -
R1S8K about 4 years@Harsh Thanks man ! so it's a type def of
unsigned char
that explains a lot. So the only integer isint
, right ? -
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 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
orint
because the compiler would optimize the use of RAM or flash according to what fills that register, am I right ? -
Harsh about 4 years@R1S8K Hmm... I am not sure; but I am strongly inclined towards that not being the case. :)
-
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 likeconst dataType variableName[] PROGMEM = {data0, data1, data3…};
-
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 thatusing 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 innumerical_chars
, and the char types aren't either of course. -
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 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 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 about 3 yearsvariable size will increase to 4 byte from 1 byte. I want a 1 byte variable. any help?
-
Sadegh about 3 years@PeteBecker variable size will increase to 4 byte from 1 byte. I want a 1 byte variable. any help?
-
Sadegh about 3 yearsvariable 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 over 2 yearsThis 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 about 2 yearsIngenious, I have a templated << operator for uint8_t and float, and this one works perfectly
-
Matt Messersmith about 2 yearsAren'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.