39

我知道在 C# 中你可以使用 String.Format 方法。但是你如何在 C++ 中做到这一点?是否有允许我将字节转换为十六进制的功能?只需要将 8 字节长的数据转换为十六进制,我该怎么做?

4

10 回答 10

74

如果要使用 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 
于 2012-05-15T11:55:09.920 回答
36

好吧,您可以一次将一个字节(无符号字符)转换为这样的数组

char buffer [17];
buffer[16] = 0;
for(j = 0; j < 8; j++)
    sprintf(&buffer[2*j], "%02X", data[j]);
于 2012-05-15T10:49:34.413 回答
19

C:

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;
}
于 2014-11-27T14:32:09.923 回答
9

在现代 C++ 中打印任意结构

到目前为止,所有答案都只告诉您如何打印整数数组,但我们也可以打印任意结构,只要我们知道它的大小。下面的示例创建了这样的结构并通过其字节迭代指针,将它们打印到输出:

#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),然后是msgSize2 个字节 ( 24 00),然后是 4 个填充字节,之后是someId( 34 12 00 00 00 00 00 00) 和anotherId( 78 56 00 00 00 00 00 00)。然后isFoo,它占用 1 个字节 ( 01) 和isBar,另一个字节 ( 01),接着是 6 个字节的填充,最后以双字段的 IEEE 754 标准表示结束floatingPointValue

另请注意,所有值都表示为小端(最低有效字节在前),因为这是在英特尔平台上编译和运行的。

于 2017-11-24T13:07:06.553 回答
6

您可以使用std::format类似于String.FormatC# 的 C++20 来执行此操作:

std::string s = std::format("{:x}", std::byte(42)); // s == 2a

std::format广泛使用之前,您可以使用基于 ( godbolt )的 {fmt} 库std::format

std::string s = fmt::format("{:x}", std::byte(42)); // s == 2a

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

于 2021-09-25T15:51:20.063 回答
3

这是 Nibble to 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;
    }
}
于 2013-09-05T13:45:32.987 回答
2

我不知道比以下更好的方法:

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

您可以使用 Nibble to Hex 方法加快速度

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

}
于 2013-08-02T20:21:37.637 回答
1

另一个答案,如果字节数组被定义为char[],大写并用空格分隔。

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

于 2021-02-19T20:05:46.157 回答
0

使用 C++ 流并在之后恢复状态

这是如何将字节打印为十六进制的变体?但:

主文件

#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 上测试。

于 2018-12-07T16:42:19.090 回答
0

另一个 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)<<' ';
});

可执行代码在这里

于 2021-04-22T20:22:18.967 回答