Home > Back-end >  c stringstream read doesn't seem to read the whole buffer
c stringstream read doesn't seem to read the whole buffer

Time:09-21

I have the following code: https://godbolt.org/z/9aqqe5eYh

#include<string>
#include<sstream>
#include<iomanip>
#include<iostream>

int main() {
  std::string line = "fa0834dd";

  for(int i = 0; i < line.length(); i  = 2) {
    std::stringstream ss;
    std::uint8_t byte;

    ss << std::hex << line.substr(i, 2);
    std::cout << ss.str() << " ";
    ss >> byte;
    std::cout << std::hex << std::setw(2) << byte << std::endl;
  }
}

Ideally, this takes in a string of hex numbers, splits them into bytes (pair of hex digits) and stores it into bytes (for illustrative purposes, I use only one std::uint8_t above). The above code outputs this:

Program returned: 0
Program stdout
fa  f
08  0
34  3
dd  d

Which seems kinda odd. An std::uint8_t should be enough to store 2 hex character's worth of data. But it seems like ss >> byte only stores the front hex character. My guess is that:

ss << std::hex << line.substr(i, 2);

actually stores each hex character as 1 byte?

How would I fix the above code to generate an single-byte value equal to 2 hex characters in the string?

CodePudding user response:

stringstream is not eligible for parsing the character representation into a value in byte.

You may use something lik strtol to actually parse the string into value.

#include<string>
#include<sstream>
#include<iomanip>
#include<iostream>

int main() {
  std::string line = "fa0834dd";

  for(int i = 0; i < line.length(); i  = 2) {
    std::string ss = line.substr(i,2);
    
    std::cout << ss << " ";

    std::uint8_t byte = static_cast<std::uint8_t>(strtol(ss.c_str(), NULL, 16));
    std::cout << std::hex << static_cast(byte) << std::endl;
  }
}

Ref post

CodePudding user response:

The problem is that std::hex only applies to integer input/output, and while uint8_t is technically an integer, it just an unsigned char underneath, and iostream will input and output its character value rather than its integer value. In other words, your loop puts two characters into the stringstream, and then extracts the first character back out again.

If you want to convert hex data to native integer types, you can use std::stoi or a similar function. For example (extracting the first byte only):

std::string hexdata = "01020304";
size_t length;

// attempt to convert just the first two characters
uint8_t firstbyte = std::stoi(hexdata.substr(0, 2), &length, 16);

// "length" is set to the number of characters successfully parsed
// so if it is not the same number of characters that you supplied,
// then there's an issue. In this case, we are expected 2.
if (length != 2)
{
    std::cerr << "was that hex??" << std::endl;
}
else
{
    // you'll need to cast it to an integer type in order to see its integer value
    // otherwise iostreams will just output the character value
    std::cout << "value of byte is " << static_cast<int>(firstbyte) << std::end;
}

std::stoi may also throw an exception if there was absolutely no conversion possible at all (e.g. none of the characters in the supplied string were convertible).

  • Related