如何在 c++ 中将无符号字符打印为十六进制 使用ostream?
我想在 C++ 中使用无符号 8 位变量。 就算术而言, unsigned char
或 uint8_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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
使用:
如果你想用前导零填充,那么:
由于我们使用的是 C 风格的强制转换,为什么不彻底解决 C++ 终端的缺陷并使用宏呢!
然后你可以说
编辑:话虽如此,MartinStettner 的解决方案要好得多!
Use:
And if you want padding with leading zeros then:
As we are using C-style casts, why not go the whole hog with terminal C++ badness and use a macro!
you can then say
Edit: Having said that, MartinStettner's solution is much nicer!
我建议使用以下技术:
它编写起来很短,与原始解决方案具有相同的效率,并且它允许您选择使用“原始”字符输出。 而且它是类型安全的(不使用“邪恶”宏:-))
I would suggest using the following technique:
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 :-))
您可以在 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 打印为十六进制的最简单、最正确的技术是
读者摘要版本,其工作原理是一元 + 运算符强制将 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
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.
嗯,这对我有用:
如果你按照建议转换
(int)
,如果它的最高有效位是 1,它可能会在a
的左边添加 1。所以这样做二进制 AND 运算保证输出的左侧位将被 0 填充,并将其转换为 unsigned int ,强制 cout 将其打印为十六进制。我希望这有帮助。
Well, this works for me:
If you just cast
(int)
as suggested it might add 1s to the left ofa
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.
在 C++20 中,您可以使用
std::format
< /a> 执行此操作:输出:
如果不可用,您可以使用 {fmt} 库 ,
std::format
是基于的。 {fmt} 还提供了print
功能,使这变得更加简单和高效 (godbolt< /a>):免责声明:我是 {fmt} 和 C++20
std::format
的作者。In C++20 you can use
std::format
to do this:Output:
If it is not available you can use the {fmt} library,
std::format
is based on. {fmt} also provides theprint
function that makes this even easier and more efficient (godbolt):Disclaimer: I'm the author of {fmt} and C++20
std::format
.嗯,看来我昨天重新发明了轮子...但是,嘿,至少这次是一个通用轮子:)
char
打印有两个十六进制数字,short
s 具有 4 个十六进制数字等等。Hm, it seems I re-invented the wheel yesterday... But hey, at least it's a generic wheel this time :)
char
s are printed with two hex digits,short
s with 4 hex digits and so on.我认为TrungTN和anon的答案还可以,但是MartinStettner实现hex()函数的方法并不是很简单,而且考虑到hex << ,也太黑暗了。 (int)mychar 已经是一种解决方法。
这是我制作“<<”的解决方案 操作符更简单:
不值得实现流操作符:-)
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:
It's just not worthy implementing a stream operator :-)
我认为我们缺少对这些类型转换如何工作的解释。
char
是依赖于平台的有符号
或无符号
。 在 x86 中,char
相当于signed char
。当整型(
char
、short
、int
、long
)转换为更大容量类型时,对于无符号
类型,通过在左侧添加零来进行转换;对于有符号
类型,则通过符号扩展来进行转换。 符号扩展包括将原始数字的最高有效(最左边)位复制到左侧,直到达到目标类型的位大小。因此,如果我默认系统处于
signed char
中,并且我这样做:我们将获得
F...F0
,因为前导1
位已被延长。如果我们想确保在任何系统中只打印
F0
,我们就必须进行额外的中间类型转换为unsigned char
以便添加零,并且,因为它们对于只有 8 位的整数来说并不重要,因此不会打印:这会产生
F0
I think we are missing an explanation of how these type conversions work.
char
is platform dependentsigned
orunsigned
. In x86char
is equivalent tosigned 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 ofunsigned
types and by sign extension forsigned
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:We would obtain
F...F0
since the leading1
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 anunsigned char
so that zeros are added instead and, since they are not significant for a integer with only 8-bits, not printed:This produces
F0
我会像 MartinStettner 那样做,但添加一个额外的数字位数参数:
因此默认情况下有两位数字,但可以设置四位、八位或其他任何数字(如果您愿意)。
例如。
这可能看起来有点矫枉过正,但正如 Bjarne 所说:“库应该易于使用,而不是易于编写”。
I'd do it like MartinStettner but add an extra parameter for number of digits:
So you have two digits by default but can set four, eight, or whatever if you want to.
eg.
It may seem like overkill but as Bjarne said: "libraries should be easy to use, not easy to write".
我建议:
摘自:
http://www.cprogramming.com/tutorial/iomanip.html
I would suggest:
Taken from:
http://www.cprogramming.com/tutorial/iomanip.html
您可以尝试以下代码:
输出:
a is 0; b 为 ff
a 为 00; b 为 ff
a 为 00; b 是 FF
You can try the following code:
Output:
a is 0; b is ff
a is 00; b is ff
a is 00; b is FF
我在 win32/linux(32/64 位)上使用以下命令:
I use the following on win32/linux(32/64 bit):
我意识到这是一个老问题,但它也是搜索我遇到的非常相似问题的解决方案的顶级谷歌结果,即希望在模板类中实现任意整数到十六进制字符串的转换。 我的最终目标实际上是一个
Gtk::Entry
子类模板,它允许以十六进制编辑各种整数宽度,但这不是重点。这将一元
operator+
技巧与
中的std::make_unsigned
结合起来,以防止符号扩展负数int8_t 的问题
或signed char
值出现在 这个答案无论如何,我相信这是比任何其他通用解决方案更简洁。 它应该适用于任何有符号或无符号整数类型,并且如果您尝试使用任何非整数类型实例化该函数,则会抛出编译时错误。
一些示例用法:
更新: 或者,如果您不喜欢使用
ostringstream
的想法,您可以将模板和一元运算符技巧与接受的答案的结构结合起来基于以下内容的解决方案。 请注意,在这里,我通过删除对整数类型的检查来修改模板。make_unsigned
的使用可能足以保证编译时类型安全。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 withstd::make_unsigned
from<type_traits>
to prevent the problem of sign-extending negativeint8_t
orsigned char
values that occurs in this answerAnyway, 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.
Some example usage:
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. Themake_unsigned
usage might be enough for compile time type safety guarantees.我想发布我基于@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
和_Hex
和hex_sep
分别。_print_byte
是从operator<<
中提取出来的,带有函数参数size
,以避免实例化不同的大小
。关于二进制代码膨胀的更多信息:
正如改进 3 中提到的,无论
hex
和hex_sep
使用得多么广泛,二进制代码中只会存在(几乎)重复的函数的两个副本:_print_byte
和_print_byte
。 您可能会意识到,也可以使用完全相同的方法消除这种重复:添加函数参数sep
。 是的,但如果这样做,则需要运行时if(sep)
。 我想要一个可以在程序中广泛使用的通用库实用程序,因此我在重复而不是运行时开销上做出了妥协。 我通过使用编译时if
实现了这一点:C++11std::conditional
,函数调用的开销有望通过inline
优化掉代码>.hex_print.h:
hex_print.tcc:
测试:
输出:
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:
operator<<
should be ofconst
reference type. In @FredOverflow's code,h.x >>= 4
changes outputh
, which is surprisingly not compatible with standard library, and typeT
is requared to be copy-constructable.CHAR_BITS
is a multiple of 4. @FredOverflow's code assumeschar
is 8-bits, which is not always true, in some implementations on DSPs, particularly, it is not uncommon thatchar
is 16-bits, 24-bits, 32-bits, etc.improve:
std::uppercase
. Because format output is used in_print_byte
, standard library manipulators are still available.hex_sep
to print separate bytes (note that in C/C++ a 'byte' is by definition a storage unit with the size ofchar
). Add a template parameterSep
and instantiate_Hex<T, false>
and_Hex<T, true>
inhex
andhex_sep
respectively._print_byte
is extracted out ofoperator<<
, with a function parametersize
, to avoid instantiation for differentSize
.More on binary code bloat:
As mentioned in improvement 3, no matter how extensively
hex
andhex_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 parametersep
. Yes, but if doing so, a runtimeif(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-timeif
: C++11std::conditional
, the overhead of function call can hopefully be optimized away byinline
.hex_print.h:
hex_print.tcc:
test:
output:
de ad be ef DEADBEEF
如果您使用预填充和签名字符,请注意不要附加不需要的“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;
这也将起作用:
This will also work:
我曾经用过这种方式。
I have used in this way.