我知道在C#中可以使用String.Format方法。但是在C++中要怎么做呢?是否有一种方法可以将一个字节转换为十六进制?只需要将一个长度为8字节的数据转换为十六进制,我该怎么做呢?
我知道在C#中可以使用String.Format方法。但是在C++中要怎么做呢?是否有一种方法可以将一个字节转换为十六进制?只需要将一个长度为8字节的数据转换为十六进制,我该怎么做呢?
如果您想使用C++流而不是C函数,可以执行以下操作:
int ar[] = { 20, 30, 40, 50, 60, 70, 80, 90 };
const int siz_ar = sizeof(ar) / sizeof(int);
for (int i = 0; i < siz_ar; ++i)
cout << ar[i] << " ";
cout << endl;
for (int i = 0; i < siz_ar; ++i)
cout << hex << setfill('0') << setw(2) << ar[i] << " ";
cout << endl;
非常简单。
输出:
20 30 40 50 60 70 80 90
14 1e 28 32 3c 46 50 5a
#include <iomanip>
,而且 hex
、setfill
和 setw
都在 std
命名空间中。另外 hex
是持久的,所以你可以将其放在循环之外,并且在完成后应调用 dec
,这样流就会把未来的整数值打印成十进制,假设这是你想要的。 - Drew Noakeshex
和setfill
是什么。 - jb.unsigned char
不起作用。对于新手来说,如果你有 char a = 20; cout << hex << a << endl;
,它会给你垃圾值。因为 "char
具有带有 operator<<
的 ostream 特殊重载"。所以你需要转换为例如 int
,像这样 cout << hex << (int)a << endl;
。至于打印大于 0x80
的值作为十六进制,也需要进行转换。原因是 在 c 中打印十六进制字符。 - Rick00 00 00 20 00 00 00 30
。 - Ciro Santilli OurBigBook.com你可以将一个字节(无符号字符)分别转换为数组,如下所示:
char buffer [17];
buffer[16] = 0;
for(j = 0; j < 8; j++)
sprintf(&buffer[2*j], "%02X", data[j]);
static void print_buf(const char *title, const unsigned char *buf, size_t buf_len)
{
size_t i = 0;
fprintf(stdout, "%s\n", title);
for(i = 0; i < buf_len; ++i)
fprintf(stdout, "%02X%s", buf[i],
( i + 1 ) % 16 == 0 ? "\r\n" : " " );
}
C++:
void print_bytes(std::ostream& out, const char *title, const unsigned char *data, size_t dataLen, bool format = true) {
out << title << std::endl;
out << std::setfill('0');
for(size_t i = 0; i < dataLen; ++i) {
out << std::hex << std::setw(2) << (int)data[i];
if (format) {
out << (((i + 1) % 16 == 0) ? "\n" : " ");
}
}
out << std::endl;
}
你可以使用C++20的std::format
,它类似于C#中的String.Format
:
std::string s = std::format("{:x}", std::byte(42)); // s == 2a
在 std::format
得到广泛应用之前,您可以使用 {fmt} 库。 std::format
是基于 (godbolt)。
std::string s = fmt::format("{:x}", std::byte(42)); // s == 2a
免责声明:我是 {fmt} 和 C++20 std::format
的作者。
std::format
不支持std::byte
。虽然{fmt}
支持,但是你在{fmt}
中使用的枚举类型不在std
中。 - Barry到目前为止,所有答案都只告诉您如何打印整数数组,但是我们也可以打印任意结构,只要我们知道它的大小。下面的示例创建了这样的结构,并通过其字节迭代指针,将它们打印到输出:
#include <iostream>
#include <iomanip>
#include <cstring>
using std::cout;
using std::endl;
using std::hex;
using std::setfill;
using std::setw;
using u64 = unsigned long long;
using u16 = unsigned short;
using f64 = double;
struct Header {
u16 version;
u16 msgSize;
};
struct Example {
Header header;
u64 someId;
u64 anotherId;
bool isFoo;
bool isBar;
f64 floatingPointValue;
};
int main () {
Example example;
// fill with zeros so padding regions don't contain garbage
memset(&example, 0, sizeof(Example));
example.header.version = 5;
example.header.msgSize = sizeof(Example) - sizeof(Header);
example.someId = 0x1234;
example.anotherId = 0x5678;
example.isFoo = true;
example.isBar = true;
example.floatingPointValue = 1.1;
cout << hex << setfill('0'); // needs to be set only once
auto *ptr = reinterpret_cast<unsigned char *>(&example);
for (int i = 0; i < sizeof(Example); i++, ptr++) {
if (i % sizeof(u64) == 0) {
cout << endl;
}
cout << setw(2) << static_cast<unsigned>(*ptr) << " ";
}
return 0;
}
这里是输出结果:
05 00 24 00 00 00 00 00
34 12 00 00 00 00 00 00
78 56 00 00 00 00 00 00
01 01 00 00 00 00 00 00
9a 99 99 99 99 99 f1 3f
version
占用2个字节(05 00
),其后是2个字节的msgSize
(24 00
),然后是4个字节的填充,再之后是someId
(34 12 00 00 00 00 00 00
)和anotherId
(78 56 00 00 00 00 00 00
)。接着是占用1个字节的isFoo
(01
)和另一个字节的isBar
(01
),再加上6个字节的填充,最后以IEEE 754标准表示的floatingPointValue
双精度字段结束。这是一种改良版的Nibble转Hex方法。
void hexArrayToStr(unsigned char* info, unsigned int infoLength, char **buffer) {
const char* pszNibbleToHex = {"0123456789ABCDEF"};
int nNibble, i;
if (infoLength > 0) {
if (info != NULL) {
*buffer = (char *) malloc((infoLength * 2) + 1);
buffer[0][(infoLength * 2)] = 0;
for (i = 0; i < infoLength; i++) {
nNibble = info[i] >> 4;
buffer[0][2 * i] = pszNibbleToHex[nNibble];
nNibble = info[i] & 0x0F;
buffer[0][2 * i + 1] = pszNibbleToHex[nNibble];
}
} else {
*buffer = NULL;
}
} else {
*buffer = NULL;
}
}
unsigned char byData[xxx];
int nLength = sizeof(byData) * 2;
char *pBuffer = new char[nLength + 1];
pBuffer[nLength] = 0;
for (int i = 0; i < sizeof(byData); i++)
{
sprintf(pBuffer[2 * i], "%02X", byData[i]);
}
unsigned char byData[xxx];
const char szNibbleToHex = { "0123456789ABCDEF" };
int nLength = sizeof(byData) * 2;
char *pBuffer = new char[nLength + 1];
pBuffer[nLength] = 0;
for (int i = 0; i < sizeof(byData); i++)
{
// divide by 16
int nNibble = byData[i] >> 4;
pBuffer[2 * i] = pszNibbleToHex[nNibble];
nNibble = byData[i] & 0x0F;
pBuffer[2 * i + 1] = pszNibbleToHex[nNibble];
}
sprintf()
通常被认为是危险的,有充分的理由。在这里,只要你仔细地分配了足够的空间,使用它就可以了,但一般情况下,我会避免使用它。我更喜欢使用 nibble 方法。 - cmaster - reinstate monicaconst char* szNibbleToHex
。 - lbeninichar[]
,并且大写字母之间用空格分隔,请参考以下答案。void debugArray(const unsigned char* data, size_t len) {
std::ios_base::fmtflags f( std::cout.flags() );
for (size_t i = 0; i < len; ++i)
std::cout << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (((int)data[i]) & 0xFF) << " ";
std::cout << std::endl;
std::cout.flags( f );
}
例子:
unsigned char test[]={0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
debugArray(test, sizeof(test));
01 02 03 04 05 06
又一个 C++17 的替代方案,为什么不呢!
std::cout<<std::hex<<std::setfill('0');
struct {
std::uint16_t first{666};
std::array<char,4> second{'a','b','c','d'};
} my_struct;
auto ptr = reinterpret_cast<std::byte*>(&my_struct);
auto buffer = std::vector<std::byte>(ptr, ptr + sizeof(my_struct));
std::for_each(std::begin(buffer),std::end(buffer),[](auto byte){
std::cout<<std::setw(2)<<std::to_integer<int>(byte)<<' ';
});
可执行代码在这里。
使用C++流并在之后恢复状态
这是如何将字节打印为十六进制?的一个变体,但是:
main.cpp
#include <iomanip>
#include <iostream>
int main() {
int array[] = {0, 0x8, 0x10, 0x18};
constexpr size_t size = sizeof(array) / sizeof(array[0]);
// Sanity check decimal print.
for (size_t i = 0; i < size; ++i)
std::cout << array[i] << " ";
std::cout << std::endl;
// Hex print and restore default afterwards.
std::ios cout_state(nullptr);
cout_state.copyfmt(std::cout);
std::cout << std::hex << std::setfill('0') << std::setw(2);
for (size_t i = 0; i < size; ++i)
std::cout << array[i] << " ";
std::cout << std::endl;
std::cout.copyfmt(cout_state);
// Check that cout state was restored.
for (size_t i = 0; i < size; ++i)
std::cout << array[i] << " ";
std::cout << std::endl;
}
编译并运行:
g++ -o main.out -std=c++11 main.cpp
./main.out
输出:
0 8 16 24
00 8 10 18
0 8 16 24
在Ubuntu 16.04,GCC 6.4.0上进行了测试。