42

I know in C# you can use String.Format method. But how do you do this in C++? Is there a function that allows me to convert a byte to a Hex?? Just need to convert a 8 byte long data to Hex, how do I do that?

luke
  • 36,103
  • 8
  • 58
  • 81
Danny
  • 9,199
  • 16
  • 53
  • 75

10 Answers10

79

If you want to use C++ streams rather than C functions, you can do the following:

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;

Very simple.

Output:

20 30 40 50 60 70 80 90
14 1e 28 32 3c 46 50 5a 
cs95
  • 379,657
  • 97
  • 704
  • 746
Component 10
  • 10,247
  • 7
  • 47
  • 64
  • 59
    Worth noting that you should `#include ` and that `hex`, `setfill` and `setw` are all in the `std` namespace. Further `hex` is persistent, so you can pull it outside the loop, and you should call `dec` when you're done so that the stream prints future integral values in decimal, assuming that's what you want. – Drew Noakes Aug 30 '14 at 21:29
  • 3
    Very good answer --- it could use some examples what ``hex`` and ``setfill`` are. – jb. Nov 21 '14 at 20:58
  • 8
    To expound upon @Andrew, if you have a char c and want to print values > 0x80 as hex, you need to cast it as (unsigned int)(unsigned char)c. Otherwise you'll print the 32-bit 2's complement. – jtbr Jun 27 '17 at 21:08
  • @DrewNoakes I have attempted to cover those points at: https://stackoverflow.com/a/53673624/895245 – Ciro Santilli OurBigBook.com Dec 07 '18 at 16:43
  • 3
    @jbr `unsigned char` doesn't work. For newcomers, if you have `char a = 20; cout << hex << a << endl;`, it will give you garbage. Because "`char` has a special overload for ostream with `operator<<`". So you need to cast to e.g. `int`, like `cout << hex << (int)a << endl;`. As for print values > `0x80` as hex, a casting is also required. The reason is [printing hexadecimal characters in c](https://stackoverflow.com/questions/8060170/printing-hexadecimal-characters-in-c). – Rick Nov 21 '19 at 16:12
  • Just noticed this is likely not what OP wanted. What OP wants for that array is likely `00 00 00 20 00 00 00 30`. – Ciro Santilli OurBigBook.com Aug 16 '20 at 05:41
38

Well you can convert one byte (unsigned char) at a time into a array like so

char buffer [17];
buffer[16] = 0;
for(j = 0; j < 8; j++)
    sprintf(&buffer[2*j], "%02X", data[j]);
Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112
bentech
  • 1,226
  • 15
  • 19
21

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;
}
user1763487
  • 464
  • 4
  • 6
18

You can do it with C++20 std::format which is similar to String.Format in C#:

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

Until std::format is widely available you can use the {fmt} library, std::format is based on (godbolt):

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

Disclaimer: I'm the author of {fmt} and C++20 std::format.

vitaut
  • 49,672
  • 25
  • 199
  • 336
11

Printing arbitrary structures in modern C++

All answers so far only tell you how to print an array of integers, but we can also print any arbitrary structure, given that we know its size. The example below creates such structure and iterates a pointer through its bytes, printing them to the output:

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

And here's the output:

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

Notice this example also illustrates memory alignment working. We see version occupying 2 bytes (05 00), followed by msgSize with 2 more bytes (24 00) and then 4 bytes of padding, after which comes someId (34 12 00 00 00 00 00 00) and anotherId (78 56 00 00 00 00 00 00). Then isFoo, which occupies 1 byte (01) and isBar, another byte (01), followed by 6 bytes of padding, finally ending with the IEEE 754 standard representation of the double field floatingPointValue.

Also notice that all values are represented as little endian (least significant bytes come first), since this was compiled and run on an Intel platform.

Lucio Paiva
  • 19,015
  • 11
  • 82
  • 104
4

This is a modified version of the Nibble to Hex method

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;
    }
}
Sirko
  • 72,589
  • 19
  • 149
  • 183
3

I don't know of a better way than:

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

You can speed it up by using a Nibble to Hex method

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

}
alexkasko
  • 4,855
  • 1
  • 26
  • 31
1

Yet another answer, in case the byte array is defined as char[], uppercase and separated by spaces.

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

Example:

unsigned char test[]={0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
debugArray(test, sizeof(test));

Output:

01 02 03 04 05 06

daniol
  • 115
  • 7
0

Use C++ streams and restore state afterwards

This is a variation of How do I print bytes as hexadecimal? but:

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

Compile and run:

g++ -o main.out -std=c++11 main.cpp
./main.out

Output:

0 8 16 24 
00 8 10 18 
0 8 16 24

Tested on Ubuntu 16.04, GCC 6.4.0.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
0

Another C++17 alternative because why not!

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

Executable code here.

ambushed
  • 533
  • 1
  • 5
  • 14