how do I print an unsigned char as hex in c++ using ostream?
Solution 1
I would suggest using the following technique:
struct HexCharStruct
{
unsigned char c;
HexCharStruct(unsigned char _c) : c(_c) { }
};
inline std::ostream& operator<<(std::ostream& o, const HexCharStruct& hs)
{
return (o << std::hex << (int)hs.c);
}
inline HexCharStruct hex(unsigned char _c)
{
return HexCharStruct(_c);
}
int main()
{
char a = 131;
std::cout << hex(a) << std::endl;
}
It's short to write, has the same efficiency as the original solution and it lets you choose to use the "original" character output. And it's type-safe (not using "evil" macros :-))
Solution 2
Use:
cout << "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl;
And if you want padding with leading zeros then:
#include <iomanip>
...
cout << "a is " << setw(2) << setfill('0') << hex << (int) a ;
As we are using C-style casts, why not go the whole hog with terminal C++ badness and use a macro!
#define HEX( x )
setw(2) << setfill('0') << hex << (int)( x )
you can then say
cout << "a is " << HEX( a );
Edit: Having said that, MartinStettner's solution is much nicer!
Solution 3
You can read more about this at http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ and http://cpp.indi.frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/. I am only posting this because it has become clear that the author of the above articles does not intend to.
The simplest and most correct technique to do print a char as hex is
unsigned char a = 0;
unsigned char b = 0xff;
auto flags = cout.flags(); //I only include resetting the ioflags because so
//many answers on this page call functions where
//flags are changed and leave no way to
//return them to the state they were in before
//the function call
cout << "a is " << hex << +a <<"; b is " << +b << endl;
cout.flags(flags);
The readers digest version of how this works is that the unary + operator forces a no op type conversion to an int with the correct signedness. So, an unsigned char converts to unsigned int, a signed char converts to int, and a char converts to either unsigned int or int depending on whether char is signed or unsigned on your platform (it comes as a shock to many that char is special and not specified as either signed or unsigned).
The only negative of this technique is that it may not be obvious what is happening to a someone that is unfamiliar with it. However, I think that it is better to use the technique that is correct and teach others about it rather than doing something that is incorrect but more immediately clear.
Solution 4
Well, this works for me:
std::cout << std::hex << (0xFF & a) << std::endl;
If you just cast (int)
as suggested it might add 1s to the left of a
if its most significant bit is 1. So making this binary AND operation guarantees the output will have the left bits filled by 0s and also converts it to unsigned int forcing cout to print it as hex.
I hope this helps.
Solution 5
In C++20 you'll be able to use std::format
to do this:
std::cout << std::format("a is {:x}; b is {:x}\n", a, b);
Output:
a is 0; b is ff
In the meantime you can use the {fmt} library, std::format
is based on. {fmt} also provides the print
function that makes this even easier and more efficient (godbolt):
fmt::print("a is {:x}; b is {:x}\n", a, b);
Disclaimer: I'm the author of {fmt} and C++20 std::format
.
Related videos on Youtube
Comments
-
Nathan Fellman almost 2 years
I want to work with unsigned 8-bit variables in C++. Either
unsigned char
oruint8_t
do the trick as far as the arithmetic is concerned (which is expected, since AFAIKuint8_t
is just an alias forunsigned char
, or so the debugger presents it.The problem is that if I print out the variables using ostream in C++ it treats it as char. If I have:
unsigned char a = 0; unsigned char b = 0xff; cout << "a is " << hex << a <<"; b is " << hex << b << endl;
then the output is:
a is ^@; b is 377
instead of
a is 0; b is ff
I tried using
uint8_t
, but as I mentioned before, that's typedef'ed tounsigned char
, so it does the same. How can I print my variables correctly?Edit: I do this in many places throughout my code. Is there any way I can do this without casting to
int
each time I want to print?-
tdihp over 11 yearsI think MartinStettner's answer is rather confusing, I don't think it is worth to implement an extra struct and an extra stream operator. anon's solution is straight forward and works good enough for me.
-
-
Konrad Rudolph about 15 yearsCan I convince you to eschew the evil C-style casts once and for all? stackoverflow.com/questions/527999/…
-
Admin about 15 yearsNot in this case - it's about the only place I think they are justified.
-
Admin about 15 yearsBut then he has to use casts if he actually wants them output as chars, which seems a little unnatural!
-
Dai Doan about 15 yearsI would do it the same, except to avoid the cast I would use cout << hex << int(a); It means the same thing as a cast, without the cast. :)
-
Seth Johnson almost 15 yearsAs long as we're eschewing macros: in order to be more fully C++, shouldn't you write
(int)hs.c
asstatic_cast<int>(hs.c)
? :P -
Ted about 14 yearsThere is a slight bug in your code. If you feed a negative character in the code the hex value becomes 4 bytes instead of 2. Switching to
unsigned char
fixes the problem. -
Nathan Fellman about 12 yearsWhile this does solve the problem, one of my requirements was not to have to cast to
int
whenever I want to do this, since this appears too many times in the code. -
musiphil almost 12 yearsAnother bug(?) is that the above
operator<<
changes the mode of the given stream to hexadecimal:cout << hex(a) << 100
will give you a surprise. You should store the state of the stream before modifying it, and restore it later. -
sehe over 10 yearsI like it. Succinct. No redundant info required. I'd love a bool to indicate whether upper or lowercase is desired. Or honour the
std::uppercase
andstd::nouppercase
manipulators (which manipulate thestd::ios_base::flags::uppercase
iosflag) -
daminetreg almost 10 yearsThis is a question about C++ and std::ostream not about C and printf. :)
-
James Pack about 9 yearsWhy is this not the top answer? It is short and effective.
-
Brian McFarland about 8 yearsThis technique sign-extends types smaller than
unsigned int
/int
, which means for negative signed chars (or int16_t for example), you'll get 8 nibbles of output, the first 6 of which areF
. -
To마SE over 7 years@BrianMcFarland I noticed that issue even for unsigned char (when greater than 127), so I solved it with a bitmask:
(+c & 0xFF)
. -
Craig Ringer over 6 yearsI'm truly amazed at how bad C++ is at converting
char
to hex. -
Adrian almost 5 years@To마SE, the unary
+
is unnecessary, the binary&
already converts to anint
. -
Adrian almost 5 yearsThis is the simplest and cleanest method of the bunch.
-
sep over 3 yearsI really like this answer too! I used this solution.
-
Shn about 2 yearsThis works, but any suggestion on how I can prefix characters <= 9 to have a 0 prepended?
-
VinGarcia about 2 years@Shn_Android_Dev you can do it like this: stackoverflow.com/questions/1714515/…