如何在c ++中使用ostream打印无符号字符为hex?

我想在C ++中使用无符号的8位variables。 无论是unsigned char还是uint8_t都可以完成算术运算(这是预期的,因为AFAIK uint8_t只是unsigned char的别名,或者是debugging器提供的。

问题是,如果我在C ++中使用ostream打印出variables,将它视为char。 如果我有:

 unsigned char a = 0; unsigned char b = 0xff; cout << "a is " << hex << a <<"; b is " << hex << b << endl; 

那么输出结果是:

 a is ^@; b is 377 

代替

 a is 0; b is ff 

我尝试过使用uint8_t ,但正如我之前提到的那样,它是unsigned char的typedef,所以它也是这样。 我如何正确打印我的variables?

编辑:我在我的代码中的许多地方做这个。 有没有什么办法,我可以做到这一点, 而不是每次我想打印铸造int

我会build议使用以下技术:

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

它的写法很简短,与原来的解决scheme具有相同的效率,并且可以让您select使用“原始”字符输出。 它是types安全的(不使用“邪恶的”macros:-))

使用:

 cout << "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl; 

如果你想填充前导零,那么:

 #include <iomanip> ... cout << "a is " << setw(2) << setfill('0') << hex << (int) a ; 

因为我们正在使用C风格的演员,为什么不去terminalC ++糟糕的整个猪,并使用macros!

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

你可以再说

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

编辑:话虽如此,MartinStettner的解决scheme更好!

你可以在http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/和http:://cpp.indi上阅读更多。; frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/ 。 我只是发表这个,因为上述文章的作者已经明确表示无意。

打印hex字符最简单和最正确的技术是

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

阅读器摘要版本是如何工作的,即一元+运算符强制无符号types转换为具有正确符号的整数。 所以,一个无符号的字符转换为无符号的int,一个有符号的字符转换为int,并且字符转换为unsigned int或者int,这取决于你的平台上的字符是有符号还是无符号的。而不是指定为有符号或无符号)。

这种技术唯一的缺点是,对于一个不熟悉它的人来说可能并不是很明显。 但是,我认为使用正确的方法并教导其他人更好,而不是做一些不正确的事情,而是立即清楚。

我会像MartinStettner那样做,但为数字的数量添加一个额外的参数:

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

所以默认情况下你有两位数字,但是如果你愿意的话可以设置四位,八位或者其他任何数字。

例如。

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

看起来似乎有些过火,但正如Bjarne所说:“图书馆应该易于使用,不容易写”。

我认为TrungTN和anon的答案没问题,但MartinStettner实现hex()函数的方式并不是很简单,而且太暗了,考虑到hex<<(int)mychar已经是一个解决方法。

这里是我的解决scheme,使“<<”运算符更容易:

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

这只是不值得实施一个stream操作符:-)

我会build议:

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

采取: http : //www.cprogramming.com/tutorial/iomanip.html

嗯,似乎我昨天重新发明了轮子…但是,嘿,至less这是一个通用的轮子这个时候:) char是印有两个hex数字, short s与四个hex数字等等。

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

你可以尝试下面的代码:

 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; 

输出:

a is 0; b is ff

a is 00; b is ff

a is 00; b is FF

我想发布基于@ FredOverflow的重新发明的版本。 我做了以下修改。

固定:

  • operator<< Rhs应该是const引用types。 在@FredOverflow的代码中, hx >>= 4改变了输出h ,这与标准库令人惊讶地不兼容,并且typesT被要求是可复制构造的。
  • 假设只有CHAR_BITS是4的倍数。@FredOverflow的代码假设char是8位,在DSP上的某些实现中并非总是如此,特别是char是16位,24位,32位,位等

提高:

  • 支持所有可用于整型的标准库操纵std::uppercase ,例如std::uppercase 。 由于格式输出在_print_byte ,标准库操纵器仍然可用。
  • 添加hex_sep来打印单独的字节(注意,在C / C ++中,“字节”按照定义是一个char大小的存储单元)。 添加模板参数Sep ,并分别在hexhex Sep实例化_Hex<T, false>_Hex<T, true>
  • 避免二进制代码膨胀。 函数_print_byteoperator<<提取出来,并带有函数参数 size ,以避免为不同的Size实例化。

更多关于二进制代码膨胀:

正如在改进3中提到的那样,无论使用hexhex_sep多么广泛,只有两个(几乎)重复的函数副本将以二进制代码退出: _print_byte<true>_print_byte<false> 。 你也许会意识到,使用完全相同的方法也可以消除这种重复:添加一个函数参数sep 。 是的,但如果这样做,运行时if(sep)是需要的。 我想要一个可以在程序中广泛使用的公共库实用程序,因此我牺牲了复制而不是运行时开销。 我通过使用编译时达到了这一点, if :C ++ 11 std::conditional ,函数调用的开销可以希望通过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)); } } 

testing:

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

输出:

de ad be ef DEADBEEF

我意识到这是一个古老的问题,但它也是一个顶级的谷歌search解决scheme,我有一个非常类似的问题,这是希望在模板类中实现任意整数到hexstring转换。 我的最终目标实际上是一个Gtk::Entry子类模板,它将允许编辑hex中的各种整数宽度,但这不是重点。

这将一元运算operator+技巧与来自<type_traits> std::make_unsigned结合起来,以防止在此答案中出现符号扩展负int8_tsigned char值的问题

无论如何,我相信这比其他通用解决scheme更简洁。 它应该适用于任何有符号或无符号整数types,如果试图用任何非整数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(); } 

一些示例用法:

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

更新:另外,如果你不喜欢ostringstream被使用的想法,你可以将模板和一元运算符技巧与接受的答案基于结构的解决scheme结合起来使用。 请注意,在这里,我通过删除整数types的检查来修改模板。 make_unsigned用法对于编译时types安全保证可能是足够的。

 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; 

我在win32 / linux(32/64位)上使用以下内容:

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

这也将工作:

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

我用这种方式。

  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;