如何在 c++ 中将无符号字符打印为十六进制 使用ostream?

发布于 2024-07-16 05:21:36 字数 738 浏览 4 评论 0原文

我想在 C++ 中使用无符号 8 位变量。 就算术而言, unsigned charuint8_t 都可以解决问题(这是预期的,因为 AFAIK uint8_t 只是 uint8_t 的别名code>unsigned char,或者调试器呈现它

问题是,如果我在 C++ 中使用 ostream 打印变量,它会将其视为 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,但正如我之前提到的,它被 typedef 为 unsigned char,所以它的作用是相同的

编辑:< /strong> 我在代码中的很多地方都这样做了,有什么方法可以每次我想打印时都转换为 int 吗?

I want to work with unsigned 8-bit variables in C++. Either unsigned char or uint8_t do the trick as far as the arithmetic is concerned (which is expected, since AFAIK uint8_t is just an alias for unsigned 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 to unsigned 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

夏尔 2024-07-23 05:21:36

使用:

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 风格的强制转换,为什么不彻底解决 C++ 终端的缺陷并使用宏呢!

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

然后你可以说

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

编辑:话虽如此,MartinStettner 的解决方案要好得多!

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!

原来是傀儡 2024-07-23 05:21:36

我建议使用以下技术:

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

它编写起来很短,与原始解决方案具有相同的效率,并且它允许您选择使用“原始”字符输出。 而且它是类型安全的(不使用“邪恶”宏:-))

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

猫烠⑼条掵仅有一顆心 2024-07-23 05:21:36

您可以在 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/。 我发布此内容只是因为很明显上述文章的作者无意这样做。

将 char 打印为十六进制的最简单、最正确的技术是

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

读者摘要版本,其工作原理是一元 + 运算符强制将 no op 类型转换为具有正确符号的 int。 因此,unsigned char 转换为 unsigned int,signed char 转换为 int,char 转换为 unsigned int 或 int,具体取决于 char 在您的平台上是有符号的还是无符号的(令许多人感到震惊的是 char 是特殊的)并且未指定为有符号或无符号)。

这种技术的唯一缺点是,对于不熟悉该技术的人来说,发生的事情可能并不明显。 然而,我认为最好使用正确的技术并教给其他人,而不是做一些不正确但更直接清晰的事情。

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.

绝影如岚 2024-07-23 05:21:36

嗯,这对我有用:

std::cout << std::hex << (0xFF & a) << std::endl;

如果你按照建议转换 (int) ,如果它的最高有效位是 1,它可能会在 a 的左边添加 1。所以这样做二进制 AND 运算保证输出的左侧位将被 0 填充,并将其转换为 unsigned int ,强制 cout 将其打印为十六进制。

我希望这有帮助。

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.

指尖上得阳光 2024-07-23 05:21:36

在 C++20 中,您可以使用 std::format< /a> 执行此操作:

std::cout << std::format("a is {:x}; b is {:x}\n", a, b);

输出:

a is 0; b is ff

如果不可用,您可以使用 {fmt} 库 , std::format 是基于的。 {fmt} 还提供了 print 功能,使这变得更加简单和高效 (godbolt< /a>):

fmt::print("a is {:x}; b is {:x}\n", a, b);

免责声明:我是 {fmt} 和 C++20 std::format 的作者。

In C++20 you can 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

If it is not available 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.

节枝 2024-07-23 05:21:36

嗯,看来我昨天重新发明了轮子...但是,嘿,至少这次是一个通用轮子:) char 打印有两个十六进制数字,shorts 具有 4 个十六进制数字等等。

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"[h.x & 15];
        h.x >>= 4;
    }
    os.write(buffer, sizeof buffer);
    return os;
}

Hm, it seems I re-invented the wheel yesterday... But hey, at least it's a generic wheel this time :) chars are printed with two hex digits, shorts with 4 hex digits and so on.

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"[h.x & 15];
        h.x >>= 4;
    }
    os.write(buffer, sizeof buffer);
    return os;
}
风筝在阴天搁浅。 2024-07-23 05:21:36

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

这是我制作“<<”的解决方案 操作符更简单:

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

不值得实现流操作符:-)

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

here is my solution to make "<<" 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's just not worthy implementing a stream operator :-)

贩梦商人 2024-07-23 05:21:36

我认为我们缺少对这些类型转换如何工作的解释。

char 是依赖于平台的有符号无符号。 在 x86 中,char 相当于 signed char

当整型(charshortintlong)转换为更大容量类型时,对于无符号类型,通过在左侧添加零来进行转换;对于有符号类型,则通过符号扩展来进行转换。 符号扩展包括将原始数字的最高有效(最左边)位复制到左侧,直到达到目标类型的位大小。

因此,如果我默认系统处于 signed char 中,并且我这样做:

char a = 0xF0; // Equivalent to the binary: 11110000
std::cout << std::hex << static_cast<int>(a);

我们将获得 F...F0,因为前导 1 位已被延长。

如果我们想确保在任何系统中只打印 F0 ,我们就必须进行额外的中间类型转换为 unsigned char 以便添加零,并且,因为它们对于只有 8 位的整数来说并不重要,因此不会打印:

char a = 0xF0; // Equivalent to the binary: 11110000
std::cout << std::hex << static_cast<int>(static_cast<unsigned char>(a));

这会产生 F0

I think we are missing an explanation of how these type conversions work.

char is platform dependent signed or unsigned. In x86 char is equivalent to signed char.

When an integral type (char, short, int, long) is converted to a larger capacity type, the conversion is made by adding zeros to the left in case of unsigned types and by sign extension for signed ones. Sign extension consists in replicating the most significant (leftmost) bit of the original number to the left till we reach the bit size of the target type.

Hence if I am in a signed char by default system and I do this:

char a = 0xF0; // Equivalent to the binary: 11110000
std::cout << std::hex << static_cast<int>(a);

We would obtain F...F0 since the leading 1 bit has been extended.

If we want to make sure that we only print F0 in any system we would have to make an additional intermediate type cast to an unsigned char so that zeros are added instead and, since they are not significant for a integer with only 8-bits, not printed:

char a = 0xF0; // Equivalent to the binary: 11110000
std::cout << std::hex << static_cast<int>(static_cast<unsigned char>(a));

This produces F0

秋凉 2024-07-23 05:21:36

我会像 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 所说:“库应该易于使用,而不是易于编写”。

I'd do it like MartinStettner but add an extra parameter for 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 can set four, eight, or whatever if you want to.

eg.

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

It may seem like overkill but as Bjarne said: "libraries should be easy to use, not easy to write".

滥情稳全场 2024-07-23 05:21:36

我建议:

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

摘自:
http://www.cprogramming.com/tutorial/iomanip.html

I would suggest:

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

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

じ违心 2024-07-23 05:21:36

您可以尝试以下代码:

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 为 ff

a 为 00; b 为 ff

a 为 00; b 是 FF

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

執念 2024-07-23 05:21:36

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

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();
}
再浓的妆也掩不了殇 2024-07-23 05:21:36

我意识到这是一个老问题,但它也是搜索我遇到的非常相似问题的解决方案的顶级谷歌结果,即希望在模板类中实现任意整数到十六进制字符串的转换。 我的最终目标实际上是一个 Gtk::Entry 子类模板,它允许以十六进制编辑各种整数宽度,但这不是重点。

这将一元 operator+ 技巧与 中的 std::make_unsigned 结合起来,以防止符号扩展负数 int8_t 的问题signed char 值出现在 这个答案

无论如何,我相信这是比任何其他通用解决方案更简洁。 它应该适用于任何有符号或无符号整数类型,并且如果您尝试使用任何非整数类型实例化该函数,则会抛出编译时错误。

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 的想法,您可以将模板和一元运算符技巧与接受的答案的结构结合起来基于以下内容的解决方案。 请注意,在这里,我通过删除对整数类型的检查来修改模板。 make_unsigned 的使用可能足以保证编译时类型安全。

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;

I realize this is an old question, but its also a top Google result in searching for a solution to a very similar problem I have, which is the desire to implement arbitrary integer to hex string conversions within a template class. My end goal was actually a Gtk::Entry subclass template that would allow editing various integer widths in hex, but that's beside the point.

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

Anyway, I believe this is more succinct than any other generic solution. It should work for any signed or unsigned integer types, and throws a compile-time error if you attempt to instantiate the 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();
}

Some example usage:

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 don't like the idea of the ostringstream being used, you can combine the templating and unary operator trick with the accepted answer's struct-based solution for the following. Note that here, I modified the template by removing the check for integer types. The make_unsigned usage might be enough for compile time type safety guarantees.

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;
坏尐絯 2024-07-23 05:21:36

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

修复:

  • operator<< 的 Rhs 应为 const 引用类型。 在 @FredOverflow 的代码中,hx >>= 4 更改了输出 h,令人惊讶的是,它与标准库不兼容,并且类型 T 是要求是可复制构造的。
  • 假设只有 CHAR_BITS 是 4 的倍数。@FredOverflow 的代码假设 char 是 8 位,这并不总是正确的,特别是在 DSP 上的某些实现中,它不是不常见的是 char 为 16 位、24 位、32 位等。

改进:

  • 支持所有其他可用于整数类型的标准库操纵器,例如 std::uppercase 。 由于_print_byte中使用了格式输出,因此标准库操纵器仍然可用。
  • 添加 hex_sep 以打印单独的字节(请注意,在 C/C++ 中,“字节”根据定义是大小为 char 的存储单元)。 添加模板参数 Sep 并以 hex 实例化 _Hex_Hexhex_sep 分别。
  • 避免二进制代码膨胀。 函数_print_byte是从operator<<中提取出来的,带有函数参数size,以避免实例化不同的大小

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

正如改进 3 中提到的,无论 hexhex_sep 使用得多么广泛,二进制代码中只会存在(几乎)重复的函数的两个副本:_print_byte_print_byte。 您可能会意识到,也可以使用完全相同的方法消除这种重复:添加函数参数 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));
}

}

测试:

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

输出:

de ad be ef DEADBEEF

I'd like to post my re-re-inventing version based on @FredOverflow's. I made the following modifications.

fix:

  • Rhs of operator<< should be of const reference type. In @FredOverflow's code, h.x >>= 4 changes output h, which is surprisingly not compatible with standard library, and type T is requared to be copy-constructable.
  • Assume only CHAR_BITS is a multiple of 4. @FredOverflow's code assumes char is 8-bits, which is not always true, in some implementations on DSPs, particularly, it is not uncommon that char is 16-bits, 24-bits, 32-bits, etc.

improve:

  • Support all other standard library manipulators available for integral types, e.g. std::uppercase. Because format output is used in _print_byte, standard library manipulators are still available.
  • Add hex_sep to print separate bytes (note that in C/C++ a 'byte' is by definition a storage unit with the size of char). Add a template parameter Sep and instantiate _Hex<T, false> and _Hex<T, true> in hex and hex_sep respectively.
  • Avoid binary code bloat. Function _print_byte is extracted out of operator<<, with a function parameter size, to avoid instantiation for different Size.

More on binary code bloat:

As mentioned in improvement 3, no matter how extensively hex and hex_sep is used, only two copies of (nearly) duplicated function will exits in binary code: _print_byte<true> and _print_byte<false>. And you might realized that this duplication can also be eliminated using exactly the same approach: add a function parameter sep. Yes, but if doing so, a runtime if(sep) is needed. I want a common library utility which may be used extensively in the program, thus I compromised on the duplication rather than runtime overhead. I achieved this by using compile-time if: C++11 std::conditional, the overhead of function call can hopefully be optimized away by 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;

output:

de ad be ef DEADBEEF

給妳壹絲溫柔 2024-07-23 05:21:36

如果您使用预填充和签名字符,请注意不要附加不需要的“F”

char out_character = 0xBE;
计算<< setfill('0')<< setw(2)<< 十六进制 << unsigned Short(out_character);

打印: ffbe

使用 int 而不是 ffffffbe 中的 Short 结果

为了防止不需要的 f,您可以轻松地将它们屏蔽掉。

char out_character = 0xBE;
计算<< setfill('0')<< setw(2)<< 十六进制 << 无符号短(out_character) & 0xFF;

If you're using prefill and signed chars, be careful not to append unwanted 'F's

char out_character = 0xBE;
cout << setfill('0') << setw(2) << hex << unsigned short(out_character);

prints: ffbe

using int instead of short results in ffffffbe

To prevent the unwanted f's you can easily mask them out.

char out_character = 0xBE;
cout << setfill('0') << setw(2) << hex << unsigned short(out_character) & 0xFF;

寒冷纷飞旳雪 2024-07-23 05:21:36

这也将起作用:

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

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;
}
纸短情长 2024-07-23 05:21:36

我曾经用过这种方式。

    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;

I have used in this 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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文