3

I have a hex string and want to convert this to a hex unsigned char array!

std::string hex = "0c45a1bf" unsigned char hexCh = "" [0] = "0c" [1] = "45" [2] = "a1" [3] = "bf" 

I want this bevavior shown in hexCh!

Best way over stringstream and std::hex? Have you an implementation?!

Thx

2
  • So you should go through your string and process char by char. Commented Nov 21, 2012 at 10:19
  • 1
    Clarify the question: You want to separate each pair of characters into an array of characters or store into an array of unsigned char the value of each pair of chars? Commented Nov 21, 2012 at 10:28

5 Answers 5

4

Assuming you want the values of each pair of the hex string:

std::string hex = "0c45a1bf"; int main(int argc, char **argv) { union U { unsigned int value; unsigned char components[4]; }; U u; std::stringstream SS(hex); SS >> std::hex >> u.value; std::cout << u.components[0] << '\n'; // the 0c value std::cout << u.components[1] << '\n'; // the 45 value std::cout << u.components[2] << '\n'; // the a1 value std::cout << u.components[3] << '\n'; // the bf value } 

You can read the value into an union and get each sub-part.

Sign up to request clarification or add additional context in comments.

5 Comments

This is undefined behavior, and what actually happens will depend on the system, architecture, etc.
Yes, i know that the answer isn't complete: i'm assuming that the hex string will always fit into unsigned int and i'm not thinking about alignments but... the question doesn't specify platform nor what hex format will be used, i just think that the use of an union is worth to know as a possible solution in some scope.
Reading from a member other than the last member written is undefined behavior. More significantly, in this case, you're ignoring the problem of byte order, as well as the size of an int. The size issue can easily be fixed by using uint32_t, instead of int. The byte order issue, on the other hand, has no simple solution.
@JamesKanze yes, using a fixed-size-type like uint32_t (where is it defined?, is from the standard?) could solve part of the problem but, the problem of undefined hex format and undefined lenght hex strings remains, could be a headache to process a string like aa12345678!
uint32_t is conditionally defined in <stdint.h>, from C99 or C++11. (Most C++03 compilers will have it as well, because it is in C99.) It is only defined on machines which have a 32 bit integral type, so you won't find it on some exotic machines. (Unisys has, or at least had until recently, a 36 bit architecture with 9 bit bytes, and a 48 bit architecture with sizeof(int) == 6. But such machines have become truly exotic, and most people don't have to worry about them.)
4

Use std::stringstream + std::hex:

std::stringstream ss; std::string hex = "0c45a1bf"; std::vector<unsigned char> hexCh; unsigned int buffer; int offset = 0; while (offset < hex.length()) { ss.clear(); ss << std::hex << hex.substr(offset, 2); ss >> buffer; hexCh.push_back(static_cast<unsigned char>(buffer)); offset += 2; } 

Comments

1

You can either convert the entire string into a larger integral type, and pick out the bytes from that. Something like:

std::vector<unsigned char> asBytes( std::string const& input ) { std::istringstream parser( input ); uint32_t tmp; input >> std::hex >> tmp; std::vector<unsigned char> results; // The conversion implicitly does the & 0xFF results.push_back( tmp >> 24 ); results.push_back( tmp >> 16 ); results.push_back( tmp >> 8 ); results.push_back( tmp ); return results; } 

Or, you could create substrings of two characters each, create an std::istringstream for each, and input from it. You'd still have to input to a type larger than char, because >> to a character type reads one character only, and assigns it. But you can read it into an int, then convert the int to unsigned char.

unsigned char convertOneByte( std::string::const_iterator begin, std::string::const_iterator end ) { std::istringstream parser( std::string( begin, end ) ); int tmp; parser >> std::hex >> tmp; return tmp; } std::vector<unsigned char> asBytes( std::string const& input ) { std::vector<unsigned char> results; results.push_back( input.begin() , input.begin() + 2 ); results.push_back( input.begin() + 2, input.begin() + 4 ); results.push_back( input.begin() + 4, input.begin() + 6 ); results.push_back( input.begin() + 6, input.begin() + 8 ); return results; } 

(Both bits of code need a lot more error checking. They're just to give you an idea.)

Comments

0

This 2 functions together shall do the job:

This one is straightforward:

inline int char2hex(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; throw std::runtime_error("wrong char"); } 

This is little more complicated:

std::vector<unsigned char> str2hex(const std::string& hexStr) { std::vector<unsigned char> retVal; bool highPart = ((hexStr.length() % 2) == 0); // for odd number of characters - we add an extra 0 for the first one: if (!highPart) retVal.push_back(0); std::for_each(hexStr.begin(), hexStr.end(), [&](char nextChar) { if (highPart) // this is first char for the given hex number: retVal.push_back(0x10 * char2hex(nextChar)); else // this is the second char for the given hex number retVal.back() += char2hex(nextChar); highPart = !highPart; } ); return retVal; } 

And the example that it works:

int main() { std::string someHex = "c45a1bf"; std::vector<unsigned char> someUHex = str2hex(someHex); std::copy(someUHex.begin(), someUHex.end(), std::ostream_iterator<int>(std::cout << std::hex, "")); } 

Comments

0

A possible solution: (thx Denis Ermolin):

void ClassA::FuncA(unsigned char *answer) { std::string hex = "0c45a1bf"; std::stringstream convertStream; // if you have something like "0c 45 a1 bf" -> delete blanks hex.erase( std::remove(hex.begin(), hex.end(), ' '), hex.end() ); int offset = 0, i = 0; while (offset < hex.length()) { unsigned int buffer; convertStream << std::hex << hex.substr(offset, 2); convertStream >> std::hex >> buffer; answer[i] = static_cast<unsigned char>(buffer); offset += 2; i++; // empty the stringstream convertStream.str(std::string()); convertStream.clear(); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.