36

I searched char* to hex string before but implementation I found adds some non-existent garbage at the end of hex string. I receive packets from socket, and I need to convert them to hex strings for log (null-terminated buffer). Can somebody advise me a good implementation for C++?

Thanks!

Alex Martian
  • 3,423
  • 7
  • 36
  • 71
Roman
  • 519
  • 1
  • 5
  • 8
  • 1
    What exactly do you mean by hex string? – Dan F May 23 '12 at 15:42
  • Did you try to fix the implementation? Can you post the implementation and some input/output? – dirkgently May 23 '12 at 15:43
  • 1
    "adds some non existant garbage at the end of hex string" - you're probably passing a non-null terminated buffer into a function expecting LPSTR. Not everything char* is a string. – Agent_L May 23 '12 at 16:11
  • i guess yes, can you tell me how to get hex from null-terminated buffer? – Roman May 23 '12 at 16:22
  • possible duplicate of [char\[\] to hex string exercise](http://stackoverflow.com/questions/69115/char-to-hex-string-exercise) – Ben Voigt May 24 '12 at 15:32

8 Answers8

38

Supposing data is a char*. Working example using std::hex:

for(int i=0; i<data_length; ++i)
    std::cout << std::hex << (int)data[i];

Or if you want to keep it all in a string:

std::stringstream ss;
for(int i=0; i<data_length; ++i)
    ss << std::hex << (int)data[i];
std::string mystr = ss.str();
Jorge González Lorenzo
  • 1,722
  • 1
  • 19
  • 28
  • 24
    You have to use std:setfill and std::setw to convert correctly. see: http://stackoverflow.com/a/7639754/1731454 – oferei Sep 21 '15 at 10:44
  • 4
    This answer is incorrect and will result in corrupted data. See the link in the comment above by @oferei for a correct example. – T.Coutlakis Mar 10 '20 at 19:53
  • Casting a `char*` array element directly to `int` or `unsigned int` will result in bytes over 0x7F being improperly "sign-extended". You need to first cast the `char` to `uint8_t`, then cast that to `unsigned int`, in order to correctly represent bytes. See this example: https://stackoverflow.com/questions/62934400/ – Edward Jan 10 '22 at 17:37
23

Here is something:

char const hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

for( int i = data; i < data_length; ++i )
{
    char const byte = data[i];

    string += hex_chars[ ( byte & 0xF0 ) >> 4 ];
    string += hex_chars[ ( byte & 0x0F ) >> 0 ];
}
K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • could you explain how this works? – Nam Vu Jun 21 '22 at 19:22
  • **Explanation:** Each **byte** (unsigned char) **has 8 bits**; As `8 == 4*2` and maximum number in hex is `F==15` which requires 4 bits in binary representation, you need two digits in hex to represent a byte. What code does is, it bitmasks (logical AND) each byte first with `1111 0000` then `0000 1111` to only get the part of binary number that fits in a single hex digit; Then if it is the first 4 digit (first hex digit in a two digits pair) of the binary number, we shift it right to use it as `0 to 15`, and then we use it as `hex_chars` index. Hope I helped – Shahaboddin Aug 13 '23 at 07:44
14

The simplest:

int main()
{
    const char* str = "hello";
    for (const char* p = str; *p; ++p)
    {
        printf("%02x", *p);
    }
    printf("\n");
    return 0;
}
demi
  • 5,384
  • 6
  • 37
  • 57
12

I've found good example here Display-char-as-Hexadecimal-String-in-C++:

  std::vector<char> randomBytes(n);
  file.read(&randomBytes[0], n);

  // Displaying bytes: method 1
  // --------------------------
  for (auto& el : randomBytes)
    std::cout << std::setfill('0') << std::setw(2) << std::hex << (0xff & (unsigned int)el);
  std::cout << '\n';

  // Displaying bytes: method 2
  // --------------------------
  for (auto& el : randomBytes)
    printf("%02hhx", el);
  std::cout << '\n';
  return 0;

Method 1 as shown above is probably the more C++ way:

Cast to an unsigned int
Use std::hex to represent the value as hexadecimal digits
Use std::setw and std::setfill from <iomanip> to format
Note that you need to mask the cast int against 0xff to display the least significant byte:
(0xff & (unsigned int)el).

Otherwise, if the highest bit is set the cast will result in the three most significant bytes being set to ff.

Alex Martian
  • 3,423
  • 7
  • 36
  • 71
7

Code snippet above provides incorrect byte order in string, so I fixed it a bit.

char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',   'B','C','D','E','F'};

std::string byte_2_str(char* bytes, int size) {
  std::string str;
  for (int i = 0; i < size; ++i) {
    const char ch = bytes[i];
    str.append(&hex[(ch  & 0xF0) >> 4], 1);
    str.append(&hex[ch & 0xF], 1);
  }
  return str;
}
Tomas
  • 176
  • 3
5

Using boost:

#include <boost/algorithm/hex.hpp>

std::string s("tralalalala");
std::string result;
result.reserve(s.size() * 2);
boost::algorithm::hex_lower(s, std::back_inserter(result));

https://godbolt.org/z/jEc1vPW38

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Why does the boost::algorithm::hex always converts the characters to upper case? How to make it not change the case? – polapts Oct 30 '19 at 18:51
  • [boost::algorithm::hex_lower](https://www.boost.org/doc/libs/1_62_0/libs/algorithm/doc/html/boost/algorithm/hex_lowe_idm46408636289664.html) – Marek R Nov 01 '19 at 08:30
0

You can try this code for converting bytes from packet to a null-terminated string and store to "string" variable for processing.

const int buffer_size = 2048;
// variable for storing buffer as printable HEX string
char data[buffer_size*2];
// receive message from socket
int ret = recvfrom(sock, buffer, sizeofbuffer, 0, reinterpret_cast<SOCKADDR *>(&from), &size);
// bytes converting cycle
for (int i=0,j=0; i<ret; i++,j+=2){ 
    char res[2]; 
    itoa((buffer[i] & 0xFF), res, 16);
        if (res[1] == 0) {
            data[j] = 0x30; data[j+1] = res[0];
        }else {
            data[j] = res[0]; data[j + 1] = res[1];
        }
}
// Null-Terminating the string with converted buffer
data[(ret * 2)] = 0;

When we send message with hex bytes 0x01020E0F, variable "data" had char array with string "01020e0f".

-5

You could use std::hex

Eg.

std::cout << std::hex << packet;
jaho
  • 4,852
  • 6
  • 40
  • 66
  • 8
    I don't know what you think `std::hex` changes for `char*` output, but you should build a working demo. – Ben Voigt May 24 '12 at 15:37