Hex_string to uint8_t msg[] - c++

I want convert the characters in hex string
"0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98"
to uint8_t msg[] and do not understand how to do it.
It seems simple, but have been unable to figure it out. I want to convert each character to a uint8_t hex value. For example if I have
string result = "0123456789abcdef";
How do I convert the string to:
uint8_t msg[] = "0123456789abcdef";

This func (thanks Converting a hex string to a byte array )
vector<uint8_t> HexToBytes(const string& hex) {
vector<uint8_t> bytes;
for (unsigned int i = 0; i < hex.length(); i += 2) {
string byteString = hex.substr(i, 2);
uint8_t byte = (uint8_t) strtol(byteString.c_str(), nullptr, 16);
bytes.push_back(byte);
}
return bytes;
}
using the above function we get the vector of bytes and call the method data()
I want to thank the community now everything is working correctly. Thanks for the comments, I was already desperate that I could not do such a simple thing.
Special thanks to #johnny-mopp

Edit - Updated to ready bytes not characters
Rather than using .substr() and calling C strtol and casting to uint8_t, you can simply use an istringstream along with std::setbase(16) to read the bytes as unsigned values directly into your vector<uint8_t> msg. See std::setbase.
For instance you can create an istringstream from your string containing the hex characters, and then along with your vector of uint8_t and a temporary unsigned to read directly into before pushing back into your vector you could do, e.g.
std::string result ("0123456789abcdef"); /* input hex string */
std::string s2; /* string for 2-chars */
std::istringstream ss (result); /* stringstream of result */
std::vector<uint8_t> msg; /* vector of uint8_t */
while ((ss >> std::setw(2) >> s2)) { /* read 2-char at a time */
unsigned u; /* tmp unsigned value */
std::istringstream ss2 (s2); /* create 2-char stringstream */
ss2 >> std::setbase(16) >> u; /* convert hex to unsigned */
msg.push_back((uint8_t)u); /* add value as uint8_t */
}
In that way, each 2 characters in result read using std::setw(2) are used to create a 2-character stringstream that is then converted a an unsigned value using std::setbase(16). A complete example would be:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
int main (void) {
std::string result ("0123456789abcdef"); /* input hex string */
std::string s2; /* string for 2-chars */
std::istringstream ss (result); /* stringstream of result */
std::vector<uint8_t> msg; /* vector of uint8_t */
while ((ss >> std::setw(2) >> s2)) { /* read 2-char at a time */
unsigned u; /* tmp unsigned value */
std::istringstream ss2 (s2); /* create 2-char stringstream */
ss2 >> std::setbase(16) >> u; /* convert hex to unsigned */
msg.push_back((uint8_t)u); /* add value as uint8_t */
}
std::cout << "string: " << result << "\nmsg: \n";
for (auto& h : msg) /* for each element of msg, output hex value */
std::cout << "\t" << std::setfill('0') << std::hex << std::setw(2)
<< (uint32_t)h << '\n';;
}
(note the cast required in the output to explicitly tell cout to treat the uint8_t value as an unsigned value rather than a uint8_t value which defaults to an character type by default.
Example Use/Output
$ ./bin/hexstr2uint8_t
string: 0123456789abcdef
msg:
01
23
45
67
89
ab
cd
ef
(note there are 8 uint8_t ("byte") values stored this time instead of 16 character values)
It's just an alternative using the C++ iostream features which avoids the need to cast things around rather than calling strtol directly (which in your case should probably be strtoul to begin with).
Manual Hex Conversion
In your last comment you indicate that using iostream and stringstream for the conversion is slow. You can attempt to optimize a bit by eliminating the stringstream and using a string::iterator to step through the string manually converting each character and forming each uint8_t byte as you go (protecting against a final nibble or 1/2-byte), e.g.
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
/* simple manual conversion of hexchar to value */
uint8_t c2hex (const char c)
{
uint8_t u = 0;
if ('0' <= c && c <= '9')
u = c - '0';
else if ('a' <= c && c <= 'f')
u = c - 'W';
else if ('A' <= c && c <= 'F')
u = c - '7';
else
std::cerr << "error: invalid hex char '" << c << "'\n";
return u;
}
int main (void) {
std::string s ("0123456789abcdef");
std::vector<uint8_t> msg;
for (std::string::iterator n = s.begin(); n != s.end(); n += 2) {
uint8_t u = c2hex (*n); /* save high-nibble */
if (n + 1 != s.end()) /* if low-nibble available */
u = (u << 4) | c2hex (n[1]); /* shift high left 4 & or */
msg.push_back(u); /* store byte in msg */
}
std::cout << "string: " << s << "\nmsg:\n";
for (auto& h : msg)
std::cout << "\t" << std::setfill('0') << std::hex
<< std::setw(2) << (unsigned)h << '\n';
}
(output is the same as above)
If you can guarantee there will always be an even number of characters in your string (bytes only and no 1/2-byte as the final-odd character), you can further optimize by removing the conditional and simply using:
uint8_t u = c2hex (n[1]) | (c2hex (*n) << 4);
Make sure you are compiling with full optimization, e.g. -O3 (or -Ofast gcc version >= 4.6) on gcc/clang and /Ox with VS.
Give that a try and compare performance, you can additionally dump the differing versions to assembly and see if there are any additional hints there.

Related

string with embedded null characters

Is there any way that I can use istringstream to read strings with embedded null characters? For example, if I have a char array "125 320 512 750 333\0 xyz". Is there any way that I could get "xyz" after the null character?
#include <iostream>
#include <sstream>
using namespace std;
int main() {
std::string stringvalues = "125 320 512 750 333\0 xyz";
cout << "val: " << stringvalues << endl;
std::istringstream iss (stringvalues);
for (int n=0; n<10; n++)
{
string val;
iss >> val;
std::cout << val << '\n';
}
return 0;
}
This is an example modified from cplusplus.com. I want to get the part after the null character, and I am curious whether I can get it without knowing the exact length of the char array. Thanks in advance.
Just properly initialize string with the proper size of the char array. The rest will follow naturally.
#include <sstream>
#include <string>
#include <cstring>
#include <iostream>
#include <iomanip>
int main() {
const char array[] = "125 320 512 750 333\0 xyz";
// to get the string after the null, just add strlen
const char *after_the_null_character = array + strlen(array) + 1;
std::cout << "after_the_null_character:" << after_the_null_character << std::endl;
// initialized with array and proper, actual size of the array
std::string str{array, sizeof(array) - 1};
std::istringstream ss{str};
std::string word;
while (ss >> word) {
std::cout << "size:" << word.size() << ": " << word.c_str() << " hex:";
for (auto&& i : word) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << (unsigned)i;
}
std::cout << "\n";
}
}
would output:
after_the_null_character: xyz
size:3: 125 hex:313235
size:3: 320 hex:333230
size:3: 512 hex:353132
size:3: 750 hex:373530
size:4: 333 hex:33333300
size:3: xyz hex:78797a
Note the zero byte after reading 333.
Is there any way that I can use istringstream to read strings with embedded null characters?
Yes. You can use any of the UnformattedInputFunctions such as the read member function to read input including null chars.
Note however that your stringvalues does not contain anything after the null char and thus neither does the string stream constructed from it. If you want a std::string that contains null chars (other than the terminating one), then you can use for example the constructor that accepts a size as second argument.
I want to get the part after the null character, and I am curious whether I can get it without knowing the exact length of the char array.
Here is a simple way:
const char* string = "125 320 512 750 333\0 xyz";
std::size_t length = std::strlen(string);
const char* xyz = string + length + 1;

Convert Hex to Byte in C++

How do you convert a hex string to short in c++?
Let's say you have
string hexByte = "7F";
How do you convert that to a byte? Which I assume it's a char or int8_t in c++
I tried:
wstring hexString = "7F";
unsigned char byte;
stringstream convert(hexString);
convert >> byte;
// converting from UTF-16 to UTF-8
#include <iostream> // std::cout, std::hex
#include <string> // std::string, std::u16string
#include <locale> // std::wstring_convert
#include <codecvt> // std::codecvt_utf8_utf16
int main ()
{
std::u16string str16 (u"\u3084\u3042"); // UTF-16 for YAA (やあ)
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> cv;
std::string str8 = cv.to_bytes(str16);
std::cout << std::hex;
std::cout << "UTF-8: ";
for (char c : str8)
std::cout << '[' << int(static_cast<unsigned char>(c)) << ']';
std::cout << '\n';
return 0;
}
http://www.cplusplus.com/reference/locale/wstring_convert/to_bytes/
Convert each character of hex input to integer type
int char2int(char input)
{
if(input >= '0' && input <= '9')
return input - '0';
if(input >= 'A' && input <= 'F')
return input - 'A' + 10;
if(input >= 'a' && input <= 'f')
return input - 'a' + 10;
throw std::invalid_argument("Invalid input string");
}
// This function assumes src to be a zero terminated sanitized string with
// an even number of [0-9a-f] characters, and target to be sufficiently large
void hex2bin(const char* src, char* target)
{
while(*src && src[1])
{
*(target++) = char2int(*src)*16 + char2int(src[1]);
src += 2;
}
}

Convert binary hex data to ASCII equivalent and store in String

I am using C++ on Arduino.
Suppose I have a stream of binary data;
binary data: 0xFF, 0x00, 0x01, 0xCC
I want to convert it to the ASCII equivalent and store it in a String object type.
The converted string should look like this "FF0001CC".
Here are some draft code.
char buffer[100];
String myString;
for (int i=0; i < numBytes; i++)
{
//assume buffer contains some binary data at this point
myString += String(buffer[i], HEX);
}
The problem with this code is that myString contains FF01CC, not FF0001CC.
My guess would be that the String class resizes each time a text is appended, that could be improved.
Assuming you know the input size and it´s constant, you could try this:
char outbuffer[numBytes*2+1];
const char* pHexTable="0123456789ABCDEF";
int iPos=0;
for(int i=0; i<numBytes; i++){
//assume buffer contains some binary data at this point
const char cHex=buffer[i];
outbuffer[iPos++]=pHexTable[(cHex>>4)&0x0f];
outbuffer[iPos++]=pHexTable[cHex&0x0f];
}
outbuffer[iPos]='\0';
There is stringstream class available in C++, it may be usable in this case. With C three bytes would be printed to a buffer with one sprintf-statement sprintf(buffer, "%02x%02x%02x", bytes[0], bytes[1], bytes[2]) (preferably snprintf).
#include <sstream>
#include <iostream>
#include <iomanip>
int main(void)
{
std::stringstream ss;
unsigned char bytes[] = {0xff, 0x00, 0xcc};
ss << std::hex;
// This did not work, 00 was printed as 0
// ss << std::setfill('0') << std::setw(2)
// ...
// ss << (unsigned int)bytes[i]
for (int i=0; i<3; i++) {
unsigned int tmp = bytes[i];
ss << (tmp >> 4) << (tmp & 0xf);
}
std::cout << ss.str();
return 0;
}
As understand numBytes can be bigger than 3 or 4 (otherwise why buffer size is 100?)
Also I prefer to use C++ classes when working with string (you need string, not char[]?).
Consider the following example with stringstream class (just include sstream and iomanip standard headers):
string myString;
stringstream myStringStream;
myStringStream << setbase(16);
myStringStream << uppercase;
for (int i = 0; i < numBytes; i++)
{
myStringStream << (0xFF & (unsigned int) buffer[i]);
}
myString = myStringStream.str();
I can not compare the speed of my example with other answers, but this solution is really C++ approach for buffer of any size.

Convert array of uint8_t to string in C++

I have an array of type uint8_t. I want to create a string that concatenates each element of the array. Here is my attempt using an ostringstream, but the string seems to be empty afterward.
std::string key = "";
std::ostringstream convert;
for (int a = 0; a < key_size_; a++) {
convert << key_arr[a]
key.append(convert.str());
}
cout << key << endl;
Try this:
std::ostringstream convert;
for (int a = 0; a < key_size_; a++) {
convert << (int)key[a];
}
std::string key_string = convert.str();
std::cout << key_string << std::endl;
The ostringstream class is like a string builder. You can append values to it, and when you're done you can call it's .str() method to get a std::string that contains everything you put into it.
You need to cast the uint8_t values to int before you add them to the ostringstream because if you don't it will treat them as chars. On the other hand, if they do represent chars, you need to remove the (int) cast to see the actual characters.
EDIT: If your array contains 0x1F 0x1F 0x1F and you want your string to be 1F1F1F, you can use std::uppercase and std::hex manipulators, like this:
std::ostringstream convert;
for (int a = 0; a < key_size_; a++) {
convert << std::uppercase << std::hex << (int)key[a];
}
If you want to go back to decimal and lowercase, you need to use std::nouppercase and std::dec.
Probably the easiest way is
uint8_t arr[];
// ...
std::string str = reinterpret_cast<char *>(arr);
or C-style:
std::string str = (char *) arr;

How do I convert from ASCII to hex values and also increment char pointers?

int main()
{
ifstream infile;
infile >> std::noskipws;
size_t size = 0;
infile.open("tworecords.dat", ios::binary);
if(infile.is_open())
{
infile.seekg(0, ios::end);
size = infile.tellg();
infile.seekg(0, ios::beg);
char *buffer = new char [size];
infile.read(buffer, size);
infile.close();
for(int i=0; i <59; i++)
{
c1 = (*buffer);
buffer++;
cout << c1 << endl;
}
std::cout.write (buffer, size);
cout << endl;
delete[] buffer;
}
return 0;
}
I'm reading in the data values from the file, and they appear in ASCII format. How do I make it so that I can see the values as hex values?
My second question is how do I increment char pointers to increase 1 by one, so that it reads one value at a time, like I am attempting to do in the code?
This might get you started. Annotated code:
#include <iomanip>
#include <iostream>
int main() {
// set integer output to uppercase-, hex-mode
// with '0' as fill character for small byte values
std::cout << std::hex << std::uppercase << std::setfill('0');
// declare a buffer
// note that you could use a std::vector<char> for your reads as well
std::string input;
// read a sequence of bytes (TODO: replace with reading from file)
while(std::getline(std::cin, input)) {
// iterate over the bytes as unsigned chars (not signed!)
// to support characters in the negative byte value range (>7F)
// (using C++11 range-based for loop)
for (unsigned char i : input)
// set width format for each value to 2 (00 to FF)
// (setting is only active for the next insert operation)
// insert the value as a multibyte integer
// to get the proper basic_ostream::operator<< overload
std::cout << std::setw(2) << static_cast<int>(i);
std::cout << std::endl;
}
}
Usage Example:
$ g++ test.cc -std=c++11
$ echo "Hello World" | ./a.out
48656C6C6F20576F726C64
References:
http://en.cppreference.com/w/cpp/io/manip/hex
http://en.cppreference.com/w/cpp/io/manip/uppercase
http://en.cppreference.com/w/cpp/io/manip/setfill
http://en.cppreference.com/w/cpp/io/manip/setw
http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt
http://en.cppreference.com/w/cpp/language/range-for
As for your other question about how to iterate a character array, you have a couple of options. See this code example:
#include <iostream>
int main() {
// declare buffer and size
// intentionally left out null-termination and sizeof()
// for the purpose of this demonstration
char buf[] = {'a','b','c','d','e'};
std::size_t size = 5;
// iterate using array indexing
for (std::size_t i = 0; i < size; i++) std::cout << buf[i];
std::cout << "\n";
// iterate using pointer
for (char *p = buf; p != buf+size; p++) std::cout << *p;
std::cout << "\n";
}
Note that you can (and should) use a std::vector<char> as a buffer. This has some advantages. Biggest ones: trivial to pass in and out of functions, you can always call for the size() of the buffer, and, memory management is done by the standard library.
For example (untested code):
{
// declare buffer of the appropriate size
std::vector<char> buffer(size);
// read data into the buffer
infile.read(&(buffer[0]), buffer.size());
infile.close();
// iterate the buffer using std::vector<char>::iterator
for (auto it = buffer.begin(); it != buffer.end(), ++it) {
// do your output operations
}
} // <-- storage duration of buffer ends automatically where the scope ends
More references:
http://en.cppreference.com/w/cpp/container/vector
http://en.cppreference.com/w/cpp/container/vector/size
http://en.cppreference.com/w/cpp/container/vector/begin
http://en.cppreference.com/w/cpp/container/vector/end
http://en.cppreference.com/w/cpp/types/size_t
http://en.cppreference.com/w/cpp/language/auto
#include <iomanip>
for(int i=0; i <size; i++) // <-- size, not 59
{
c1 = buffer[i]; // copy the i'th element of buffer. If you increment
// buffer (as in your example), you can't delete
// it later because you lost the initial address
cout << hex << c1 << dec << endl;
}
Aside from the hex-conversion I think your loop should be like the one below (see the comments):
for(int i=0; i <size; i++) // <-- size, not 59
{
c1 = buffer[i]; // copy the i'th element of buffer. If you increment
// buffer (as in your example), you can't delete
// it later because you lost the initial address
cout << c1 << endl;
}
Depending on the format of the hex numbers, if you want to output digit by digit (e.g. turn an 'A' into 10, etc. a very basic way is this:
int dec;
if (c1>='0' && c1<='9') {
dec= c1 - '0'; // e..g for '0' (ascii 48) it will make dec= (int)0.
}
else
if (c1>='A' && c1<='F') {
dec= 10 + (c1 - 'A'); // e..g for 'A' (ascii 65) it will make dec= (int)10.
}
else {
// should not happen or handle lower chase characters too
}
Another way, using sscanf would be:
// convert one hex digit from c1 into a corresponding decimal number
char hex[2];
int dec;
hex[0]= c1;
hex[1]= '\0';
sscanf(hex, "%1x", &dec);