40

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!

5
  • 1
    What exactly do you mean by hex string? Commented May 23, 2012 at 15:42
  • Did you try to fix the implementation? Can you post the implementation and some input/output? Commented May 23, 2012 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. Commented May 23, 2012 at 16:11
  • i guess yes, can you tell me how to get hex from null-terminated buffer? Commented May 23, 2012 at 16:22
  • possible duplicate of char[] to hex string exercise Commented May 24, 2012 at 15:32

8 Answers 8

37

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();
Sign up to request clarification or add additional context in comments.

3 Comments

You have to use std:setfill and std::setw to convert correctly. see: stackoverflow.com/a/7639754/1731454
This answer is incorrect and will result in corrupted data. See the link in the comment above by @oferei for a correct example.
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: stackoverflow.com/questions/62934400
27

Here is something:

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

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

    result += hex_chars[ ( byte & 0xF0 ) >> 4 ];
    result += hex_chars[ ( byte & 0x0F ) >> 0 ];
}

2 Comments

could you explain how this works?
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
14

The simplest:

int main()
{
    const char* str = "hello";
    for (const char* p = str; *p; ++p)
    {
        printf("%02x", *p);
    }
    printf("\n");
    return 0;
}

2 Comments

This only works for nul-terminate strings. So most likely, it will just give him the very same problem that prompted him to ask his question.
Also in my test, the @K-ballo solution takes less time! In nano second measure.
13

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.

2 Comments

nitpick - method 1 should use static_cast (re: the more C++ way)
Bonus, if you use a std::vector<unsigned char> (which is probably a bit better for random byte arrays), then you don't need the 0xff & part.
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;
}

2 Comments

This could either be a comment to K-ballo's answer or should be an answer (and you could mention what problem you've fixed). Please edit.
could you explain how does this work?
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

2 Comments

Why does the boost::algorithm::hex always converts the characters to upper case? How to make it not change the case?
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".

Comments

-5

You could use std::hex

Eg.

std::cout << std::hex << packet;

1 Comment

I don't know what you think std::hex changes for char* output, but you should build a working demo.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.