How to print unsigned char as hex in C ++ using ostream?

I want to work with 8-bit unsigned variables in C ++. Either unsigned char or uint8_t do the trick as far as arithmetic is concerned (which is expected since AFAIK uint8_t is just an alias for unsigned char , or so the debugger represents it.

The problem is that if I print out 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 output:

 a is ^@; b is 377 

instead

 a is 0; b is ff 

I tried using uint8_t , but as I mentioned earlier, it is typedef'ed to unsigned char , so it does the same. How to print my variables correctly?

Edit: I do this in many places throughout my code. Is there a way I can do this without dropping an int every time I want to print?

+47
c ++ formatting ostream
Mar 23 '09 at 12:42
source share
13 answers

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

This shortcut for writing, has the same efficiency as the original solution, and allows you to choose the "original" character output. And it's safe (without using the "evil" macros :-))

+46
Mar 23 '09 at 13:37
source share

Using:

 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 ; 

Since we use C-style casts, why not move the whole pig with C ++ terminal insensitivity and use a macro!

 #define HEX( x ) setw(2) << setfill('0') << hex << (int)( x ) 

you can say

 cout << "a is " << HEX( a ); 

Edit: Having said that, MartinStettner's solution is much better!

+35
Mar 23 '09 at 12:44
source share

You can learn 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 publishing this because it has become clear that the author of these articles does not intend.

The easiest and most correct way to print 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); 

Readers digest the version of how this works, so that the unary + operator forces a conversion of type op without conversion to int with the correct signature. Thus, unsigned char converts to unsigned int, signed char converts to int, and char converts to unsigned int or int depending on whether the char is signed or unsigned on your platform (it comes as a shock to many that char is special and it does not indicate both signed and unsigned).

The only negative of this method is that it cannot be obvious what happens to a stranger. However, I think it’s better to use a technique that is correct and teach others about it, rather than doing something wrong, but more clearly.

+22
Feb 05 '15 at 22:23
source share

I would do it like MartinStettner, but added an extra parameter for the number of digits:

 inline HexStruct hex(long n, int w=2) { return HexStruct(n, w); } // Rest of implementation is left as an exercise for the reader 

So, you have two digits by default, but you can set four, eight or something else if you want.

eg.

 int main() { short a = 3142; std:cout << hex(a,4) << std::endl; } 

This may seem redundant, but, as Bjarn said, "libraries should be easy to use, not just write."

+4
Mar 23 '09 at 2:00
source share

I think TrungTN and anon answer is ok, but MartinStettner's way of implementing the hex () function is not very simple and too dark, given that hex <(int) mychar is already a workaround.

here is my solution to make the "<<operator easier":

 #include <sstream> #include <iomanip> string uchar2hex(unsigned char inchar) { ostringstream oss (ostringstream::out); oss << setw(2) << setfill('0') << hex << (int)(inchar); return oss.str(); } int main() { unsigned char a = 131; std::cout << uchar2hex(a) << std::endl; } 

It just isn’t worth implementing the stream operator :-)

+4
Sep 28 '12 at 8:51
source share

I would suggest:

 std::cout << setbase(16) << 32; 

Taken from: http://www.cprogramming.com/tutorial/iomanip.html

+3
Feb 02 2018-12-12T00:
source share

Hmm, it seems like I invented a wheel yesterday ... But hey, at least it's a common movie this time :) char prints with two hexadecimal digits, short with 4 hexadecimal digits, etc ..

 template<typename T> struct hex_t { T x; }; template<typename T> hex_t<T> hex(T x) { hex_t<T> h = {x}; return h; } template<typename T> std::ostream& operator<<(std::ostream& os, hex_t<T> h) { char buffer[2 * sizeof(T)]; for (auto i = sizeof buffer; i--; ) { buffer[i] = "0123456789ABCDEF"[hx & 15]; hx >>= 4; } os.write(buffer, sizeof buffer); return os; } 
+3
Sep 04 '13 at 10:30
source share

You can try the following code:

 unsigned char a = 0; unsigned char b = 0xff; cout << hex << "a is " << int(a) << "; b is " << int(b) << endl; cout << hex << "a is " << setfill('0') << setw(2) << int(a) << "; b is " << setfill('0') << setw(2) << int(b) << endl; cout << hex << uppercase << "a is " << setfill('0') << setw(2) << int(a) << "; b is " << setfill('0') << setw(2) << int(b) << endl; 

Output:

a is 0; b is ff

a is 00; b is ff

a is 00; b is ff

+2
May 7, '12 at 2:27
source share

I would like to publish my new version of re-inventing based on @FredOverflow. I made the following changes.

fix:

  • Rhs operator<< must have a const reference type. In the code, @FredOverflow hx >>= 4 changes the output of h , which is surprisingly incompatible with the standard library, and the type T , apparently, should be copyable.
  • Suppose that only CHAR_BITS is a multiple of 4. @FredOverflow assumes char is 8-bit, which is not always true, in some DSP implementations, in particular, it is not uncommon that char is 16-bit, 24-bit, 32- bit, etc.

improvements:

  • Support for all other standard library manipulators available for integral types, for example. std::uppercase . Since the output format is used in _print_byte , standard library manipulators are still available.
  • Add hex_sep to print individual bytes (note that in C / C ++, a β€œbyte” is by definition a storage unit with char size). Add the Sep template parameter and instantiate _Hex<T, false> and _Hex<T, true> in hex and hex_sep respectively.
  • Avoid bloating binary code. The _print_byte function _print_byte extracted from operator<< with the size function parameter to avoid creating an instance for different size .

More on bloating binary:

As mentioned in improvement 3, no matter how widely used hex and hex_sep , only two copies of the (almost) duplicated function come out in binary: _print_byte<true> and _print_byte<false> . And you could understand that this duplication can also be eliminated using exactly the same approach: add the Sep function parameter. Yes, but if so, if(sep) runtime is required. I want to use a common library utility that can be widely used in the program, so I compromised the duplication, not the execution time overhead. I achieved this using if : C ++ 11 std::conditional compilation time, the overhead of calling a function can hopefully be optimized for inline .

hex_print.h:

 namespace Hex { typedef unsigned char Byte; template <typename T, bool Sep> struct _Hex { _Hex(const T& t) : val(t) {} const T& val; }; template <typename T, bool Sep> std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h); } template <typename T> Hex::_Hex<T, false> hex(const T& x) { return Hex::_Hex<T, false>(x); } template <typename T> Hex::_Hex<T, true> hex_sep(const T& x) { return Hex::_Hex<T, true>(x); } #include "misc.tcc" 

hex_print.tcc:

 namespace Hex { struct Put_space { static inline void run(std::ostream& os) { os << ' '; } }; struct No_op { static inline void run(std::ostream& os) {} }; #if (CHAR_BIT & 3) // can use C++11 static_assert, but no real advantage here #error "hex print utility need CHAR_BIT to be a multiple of 4" #endif static const size_t width = CHAR_BIT >> 2; template <bool Sep> std::ostream& _print_byte(std::ostream& os, const void* ptr, const size_t size) { using namespace std; auto pbyte = reinterpret_cast<const Byte*>(ptr); os << hex << setfill('0'); for (int i = size; --i >= 0; ) { os << setw(width) << static_cast<short>(pbyte[i]); conditional<Sep, Put_space, No_op>::type::run(os); } return os << setfill(' ') << dec; } template <typename T, bool Sep> inline std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h) { return _print_byte<Sep>(os, &h.val, sizeof(T)); } } 

Test:

 struct { int x; } output = {0xdeadbeef}; cout << hex_sep(output) << std::uppercase << hex(output) << endl; 

exit:

de ad be ef DEADBEEF

+1
Nov 01 '13 at 12:50
source share

I understand that this is an old question, but it is also a true Google result in finding a solution to a very similar problem that I have, which is the desire to implement an arbitrary integer with hexadecimal string conversions in the template class. My final goal was actually a template subclass of Gtk::Entry that would allow editing various integer widths in hexadecimal format, but this is next to the dot.

This combines the operator+ unary trick with std::make_unsigned from <type_traits> to prevent the problem of meaningful negative int8_t or signed char values ​​that occur in this answer

In any case, I think this is more eloquent than any other general solution. It should work for any signed or unsigned integer types and throws a compile-time error if you try to instantiate a function with any non-integer types.

 template < typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type > std::string toHexString(const T v) { std::ostringstream oss; oss << std::hex << +((typename std::make_unsigned<T>::type)v); return oss.str(); } 

Example usage example:

 int main(int argc, char**argv) { int16_t val; // Prints 'ff' instead of "ffffffff". Unlike the other answer using the '+' // operator to extend sizeof(char) int types to int/unsigned int std::cout << toHexString(int8_t(-1)) << std::endl; // Works with any integer type std::cout << toHexString(int16_t(0xCAFE)) << std::endl; // You can use setw and setfill with strings too -OR- // the toHexString could easily have parameters added to do that. std::cout << std::setw(8) << std::setfill('0') << toHexString(int(100)) << std::endl; return 0; } 

Update: Alternatively, if you do not like the idea of ​​using ostringstream , you can combine the template and unary operator trick with the decision made based on the answer to the following. Please note that here I changed the template, removing the check for integer types. Using make_unsigned might be enough to provide security like compile time.

 template <typename T> struct HexValue { T value; HexValue(T _v) : value(_v) { } }; template <typename T> inline std::ostream& operator<<(std::ostream& o, const HexValue<T>& hs) { return o << std::hex << +((typename std::make_unsigned<T>::type) hs.value); } template <typename T> const HexValue<T> toHex(const T val) { return HexValue<T>(val); } // Usage: std::cout << toHex(int8_t(-1)) << std::endl; 
+1
Mar 13 '16 at 4:54 on
source share

I use the following on win32 / linux (32/64 bit):

 #include <iostream> #include <iomanip> template <typename T> std::string HexToString(T uval) { std::stringstream ss; ss << "0x" << std::setw(sizeof(uval) * 2) << std::setfill('0') << std::hex << +uval; return ss.str(); } 
+1
May 16 '16 at 9:18
source share

This will also work:

 std::ostream& operator<< (std::ostream& o, unsigned char c) { return o<<(int)c; } int main() { unsigned char a = 06; unsigned char b = 0xff; std::cout << "a is " << std::hex << a <<"; b is " << std::hex << b << std::endl; return 0; } 
-one
Mar 23 '09 at 13:01
source share

I used that way.

  char strInput[] = "yourchardata"; char chHex[2] = ""; int nLength = strlen(strInput); char* chResut = new char[(nLength*2) + 1]; memset(chResut, 0, (nLength*2) + 1); for (int i = 0; i < nLength; i++) { sprintf(chHex, "%02X", strInput[i]& 0x00FF); memcpy(&(chResut[i*2]), chHex, 2); } printf("\n%s",chResut); delete chResut; chResut = NULL; 
-one
Sep 04 '13 at 9:58 on
source share



All Articles