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.
Related
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.
I would like to obtain this hex notation for a binary I enter in parameter:
The output I obtain and what I want:
This is the code I written, I don't have the good hex number (for the part after 5A) , what I am doing wrong ? How to convert properly the byte I read to hex ?
Thanks.
int main(int argc, char *argv[])
{
std::string parameter = "The\\Path\\To\My\exe.exe";
ifstream::pos_type size;
char * memblock;
ifstream file(parametre, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char[size];
file.seekg(0, ios::beg);
file.read(memblock, size);
file.close();
cout << "the complete file content is in memory" << endl;
string str = string(memblock, size);
string hexContent = "";
int maxColumn = 0;
std::stringstream ss;
int column = 0;
for (int i = 0; i < size; ++i)
{
ss << std::hex << (int)str[i];
if (column == 8)
{
ss << '\n';
column = 0;
}
column++;
}
std::string mystr = ss.str();
cout << mystr;
}
return 0;
}
Looks like char is signed on your system and you are the victim of sign extension. For example 0x90 is a negative, so when it's converted into an int, that negativity has to be carried through, resulting in 0xffffff90.
Solution
Read the file into unsigned char, or uint8_t from <cstdint> if it is available, instead of an array of char.
char * memblock;
becomes
uint8_t * memblock;
then
memblock = new char[size];
becomes
memblock = new uint8_t[size];
and don't convert it into a string later.
string str = string(memblock, size);
is pointless, you could just as easily have read from memblock, and undoes the unsigned-ness we've established earlier. Just read out of memblock
Do not forget to
delete[] memblock;
when you are done. That leads to
Better solution
Use a std::vector. It cleans up after itself.
std::vector<uint8_t> memblock(size);
file.seekg(0, ios::beg);
file.read(reinterpret_cast<char*>(memblock.data()), size);
//or file.read(reinterpret_cast<char*>(&memblock[0]), size); if no or data method
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;
I am trying to return a hex value inside this method. not sure where I'm going wrong. not sure how put the value into hex without using cout. have not been able to find a solution. Input value is always going to be 32 bits long
its like i want to return hex << x but thats not an option.
string StringToHex (myInstruction* RealList, int Pos)
{
string result = "11111111110000000000110011001100";
unsigned long x = strtoul(result.c_str(), &pEnd, 2);
cout<< hex << x<<endl;
return x;
}
You can use a stringstream instead of cout.
cout is just one special ostream that is created by default and is hooked up to the program's standard output. You can create other ostream objects that write to different things. std::stringstream writes to a std::string inside it.
#include <sstream>
std::string to_hex() {
unsigned int x = 256;
std::stringstream s;
s << std::hex << x;
return s.str();
}
Use std::stringstream
std::stringstream ss;
ss<< std::hex << x;
std::string res= ss.str();
If I understand your questinon, you want to return a hex value as a string, rigt? If so, then:
std::string intToHexStr (int val)
{
std::stringstream sstr;
sstr << hex << val;
std::string result;
sstr >> result;
return result;
}
Hope this helps!
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);