2

I am trying to read a file which contains bytes into a hex string.

std::ifstream infile("data.txt", std::ios_base::binary);

int length = 10;
char char_arr[length];
for (int i=0; i<length; i++)
{
     infile.get(char_arr[i]);
}
std::string hex_data(char_arr);

However the hex_data does not look like a hex string. Is there a way to convert the bytes to a hex string during reading?

Andy
  • 1,072
  • 2
  • 19
  • 33
  • Please show the input and output. – drescherjm May 11 '21 at 16:55
  • 1
    The `std::string` constructor that you are using requires a **null terminated** `char` array. – Andreas Wenzel May 11 '21 at 16:56
  • 1
    `int length = 10; char char_arr[length];` is not standard C++, see [Why aren't variable-length arrays part of the C++ standard?](https://stackoverflow.com/questions/1887097/). Either make `length` const, or else use `new[]` or better `std::vector`. – Remy Lebeau May 11 '21 at 16:57
  • 1
    @AndreasWenzel only if you use the constructor that takes just a `char*` by itself. There is another constructor that accepts a length – Remy Lebeau May 11 '21 at 16:57
  • @drescherjm the input file is binary, so there may not even be any "lines" to read from it. But, of course, there are ways to read from a binary data directly into a `std::string`. But that is pretty moot in this case. – Remy Lebeau May 12 '21 at 17:00
  • I was hoping to see my first comment answered for me to understand the question but yes I did overlook the `std::ios_base::binary` part. – drescherjm May 12 '21 at 17:48

2 Answers2

3

You are reading in raw bytes and storing them as-is into your std::string. If you want the std::string to be hex formatted, you need to handle that formatting yourself, eg:

#include <fstream>
#include <sstream>
#include <iomanip>
#include <string>

std::ifstream infile("data.txt", std::ios_base::binary);

const int length = 10;
unsigned char bytes[length];

if (infile.read(reinterpret_cast<char*>(bytes), length)) {
    size_t numRead = infile.gcount();
    std::ostringstream oss;
    for(size_t i = 0; i < numRead; ++i) {
        oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned short>(bytes[i]);
    }
    std::string hex_data = oss.str();
    ...
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

use std::stringstream object

std::stringstream stream;
stream << std::hex << static_cast<int>( your_char);
std::string result( stream.str() );
  • 2
    You should use `std::ostringstream` instead for output-only operations like this. But more important, if the `char` is signed, and its high bit is 1, this will cause the `int` to sign-extend, producing unwanted results. For example, `0x80` will be printed as `ff80`. Use unsigned chars instead to avoid that. – Remy Lebeau May 11 '21 at 17:04
  • I tried your code with `static_cast(char(0x80))` but the result also `ff80` I had to go through a double conversion to break the effect of the strong point bit: `static_cast(static_cast(char(0x80)))` – Jerome Favrou May 11 '21 at 17:41
  • Yes, scaling up a *signed* `char` to an `unsigned short` performs sign-extension, because the `char` is promoted to `int` first, then the result is casted. See [Standard C++ Behavior of Signed Char to Unsigned Int Conversion](https://stackoverflow.com/questions/41011632/). But note that in my code example, the data starts out as `unsigned char` to begin with, so the bytes don't need an extra cast to unsigned before then casted to `unsigned short`. – Remy Lebeau May 11 '21 at 17:58