C++ Converting char to byte array - c++

I need to be able to convert a QString in this format:
"0x00 0x00 0x00 0x00"
To a byte array like this:
0x00,
0x00,
0x00,
0x00
I was able to do this in Visual Studio / C# like this:
byte[] bytes = string.Split(' ').Select(s => Convert.ToByte(s, 16)).ToArray();
However I am now using Qt / C++ and I need a way to do the same thing.
What would be the easiest way to do this?

Not the most concise solution, but at least safe, I guess (invalid values are not appended):
QString string = "0x00 0x00 0x00 0x00";
QByteArray bytes;
for(auto const& x : string.split(' '))
{
bool ok;
uint val = x.toUInt(&ok, 16);
if(ok && val <= 0xff)
bytes.append(static_cast<char>(val));
}
This might be faster (invalid values are left equal to 0):
QString string = "0x00 0x00 0x00 0x00";
QStringList list = string.split(' ');
QByteArray bytes(list.size(), '\0');
for(size_t i = 0; i < list.size(); ++i)
{
bool ok;
uint val = list[i].toUInt(&ok, 16);
if(ok && val <= 0xff)
bytes[i] = static_cast<char>(val);
}
You can omit the check in both cases, if all you want is speed.

Related

How can I add a 64 bit floating point number to an unsigned char array at specific indexes (C++)

I need to add a 64 bit floating point number into an unsigned char array at specific indexes (ex. index 1 through 8).
Example unsigned char array:
unsigned char msg[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
I want to add a floating point number like 0.084, for example, which is represented as 1B2FDD240681B53F in hex (little endian) to the unsigned char array at indexes 1,2,3,4,5,6,7,8 and leave indexes 0 and 9 unchanged.
So, I would like the unsigned char array, msg, to contain the following:
msg = {0x00, 0x1B, 0x2F, 0xDD, 0x24, 0x06, 0x81, 0xB5, 0x3F, 0x00}
So far I can get a std::string with the hexadecimal representation of the example floating point value 0.084 using the following code but I'm not sure how to add the string values back into the unsigned char array:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main()
{
union udoub
{
double d;
unsigned long long u;
};
double dVal = 0.084;
udoub val;
val.d = dVal;
std::stringstream ss;
ss << std::setw(16) << std::setfill('0') << std::hex << val.u << std::endl;
std::string strValHexString = ss.str();
cout<< strValHexString << std::endl;
return 0;
}
Output:
3fb5810624dd2f1b
I tried using std::copy like in the example below to copy the values from the std::string to an unsigned char but it doesn't seem to do what I want:
unsigned char ucTmp[2];
std::copy(strValHexString.substr(0,2).begin(), strValHexString.substr(0,2).end(), ucTmp);
Looking for a C or C++ solution.
Formatting the component bytes into a hex string and then reading those back in again is a terrible waste of time and effort. Just use std::memcpy() (in C++) or memcpy (in C):
std::memcpy(&msg[1], &dVal, sizeof(dVal));
This will take care of any required pointer alignment issues. However, it will not do any 'interpretation' in terms of your endianness - but this shouldn't be a problem unless you're then transferring that byte array between different platforms.
Your example has undefined behaviour due to reading from an inactive member of a union. A well defined way to do the conversion to integer:
auto uVal = std::bit_cast<std::uint64_t>(dVal);
Now that you have the data in an integer, you can use bitwise operations to extract individual octets in specific positions:
msg[1] = (uVal >> 0x0 ) & 0xff;
msg[2] = (uVal >> 0x8 ) & 0xff;
msg[3] = (uVal >> 0x10) & 0xff;
msg[4] = (uVal >> 0x18) & 0xff;
msg[5] = (uVal >> 0x20) & 0xff;
...
This can be condensed into a loop.
Note that this works the same way regardless of endianness of the CPU. The resulting order in the array will always be little endian unlike in the direct std::memcpy approach which results in native endianness which is not necessarily little endian on all systems. However, if floating point and integers use different endianness, then the order won't be the same even with this approach.

C++ Pass bytes from char* to a BYTE*

I would like to know how to pass/COPY a sequence of bytes represented as a char* to a BYTE* in C++ in Windows.
Let's say I have this char* :
const char *ByteString = "\x3B\xC8\x74\x1B"
How would I COPY each byte from this char* to a BYTE *Bytes and vice-versa ?
EDIT: Thanks alot for everyone's help !
The definition of BYTE is:
typedef unsigned char BYTE;
which is not the same as a const char, so you'd need to convert it, but note that casting away const from something declared const to start with results in undefined behaviour and trying to actually change the data poses an even bigger risk.
BYTE* Bytes = reinterpret_cast<BYTE*>(const_cast<char*>(ByteString));
Edit: I just noticed that converting a const char* to a BYTE* was taken out of the question but I'll leave it here for now.
Copying the data (not as a zero terminated string) could be done like this:
const char ByteString[] = "\x3B\xC8\x74\x1B";
BYTE* Bytes = new BYTE[sizeof(ByteString)-1];
std::memcpy(Bytes, ByteString, sizeof(ByteString)-1);
// Use your Bytes
delete[] Bytes; // manual delete when you are done
Or better:
const char ByteString[] = "\x3B\xC8\x74\x1B";
std::basic_string<BYTE> Bytes( reinterpret_cast<const BYTE*>(ByteString), sizeof(ByteString)-1 );
// use Bytes
// Bytes.data() returns a BYTE*
// Bytes.size() returns the length.
But given the nature of what you are doing, you could probably skip these conversions and use an array of the correct type to start with:
BYTE Bytes[] = { 0xA1, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC8, 0x74, 0x1B };
or
std::basic_string<BYTE> Bytes({ 0xA1, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC8, 0x74, 0x1B });
These won't need any conversions when all you deal with is raw BYTE data. Here's an example using ReadProcessMemory and a basic_string for a buffer and pattern.
using BYTEstr = std::basic_string<BYTE>; // just for convenience
BYTEstr Buffer(1024, 0); // 1024 BYTES initialized with 0
BYTEstr Pattern({ 0xA1, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC8, 0x74, 0x1B });
ReadProcessMemory(hProcess, lpBaseAddress, Buffer.data(), Buffer.size(), &lpNumberOfBytesRead);
BYTEstr::size_type pos = Buffer.find(Pattern);
if (pos == BYTEstr::npos) {
std::cout << "Pattern not found\n";
} else {
std::cout << "Pattern found at position " << pos << "\n";
}
To respect const, use
const BYTE *Bytes = reinterpret_cast<const BYTE*>(ByteString);
and vice versa:
const char *ByteString = reinterpret_cast<const char *>(Bytes);
If you want to make copy of the buffer so that you can modify it, use
len = LenOfChrStr;
BYTE *Bytes = new BYTE[len];
memcpy(Bytes, ByteStr, len);
Given a char const * array of characters, we can make a new buffer with readwrite BYTEs for the API to possibly edit:
char const *ByteString = "\x3B\xC8\x74\x1B";
auto len = std::strlen(ByteString) + 1;
auto ptr = std::make_unique<BYTE[]>(len);
std::memcpy(ptr.get(), ByteString, len);
If you need to surrender the ownership of the memory to the function:
Func(ptr.release());
But if you want to keep the ownership yourself:
Func(ptr.get());
In MSVC (I guess this is your compiler for WinAPI application) you can make the char type unsigned with /J option (more here: https://learn.microsoft.com/en-us/cpp/build/reference/j-default-char-type-is-unsigned?view=vs-2017). If you do this, BYTE becomes the same as char and no conversion would be necessary.
Please note, this might have some other side effects in your application.

Why is my pointer array assignment not working?

I have this method prototype
bool setMacParam(const char* paramName, const uint8_t* paramValue, uint16_t size)
{
debugPrint("[setMacParam] "); debugPrint(paramName); debugPrint("= [array]");
this->loraStream->print(STR_CMD_SET);
this->loraStream->print(paramName);
for (uint16_t i = 0; i < size; ++i) {
this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(HIGH_NIBBLE(paramValue[i]))));
this->loraStream->print(static_cast<char>(NIBBLE_TO_HEX_CHAR(LOW_NIBBLE(paramValue[i]))));
}
this->loraStream->print(CRLF);
return expectOK();}
I would like to assign my variable devEUI to paramValue, I am doing this call
uint8_t DevEUI2[8] = { 0x00, 0x00, 0x00, 0x00, 0x41, 0x47, 0x30, 0x39 };
setMacParam(STR_DEV_EUI,DevEUI2,8);
However my terminal shows that paramValue is empty
[setMacParam] deveui = [array]
What do I do wrong?
debugPrint is interpretating your array as a byte array in which each byte is a char; because the first value is 0x00, incidentally is the same value for the '\0' character, that represent the "end of string".
Also the other value will be represented by their ascii representation, which is never the same as the byte value.
The print() of Serial accept some parameter that tell the function to print the ascii representation of the hex, decimal, octal or binary; maybe your SerialUSB support them too.

QT Serial send a Byte

Is there a way to send a byte to serial with QT.
I only found a function for sending chars.
serialport->write(const QByteArray &data)
I want to send a array with these three bytes in Hex: 0xF0 0x02 0x0D
Do you have something like
serialport->write(QByteArray::fromHex("F0020D"));
in mind ?
You send 8-bit values. "Hexadecimal" is just a form of notation of integer values.
QByteArray ba;
ba.resize(3);
ba[0] = 0xF0;
ba[1] = 0x02;
ba[2] = 0x0D;
serialport->write(ba);
or:
char arr[3] = {0xF0, 0x02, 0x0D};
QByteArray ba(arr, 3);
serialport->write(ba);

std::string to char array and char array to string (c++)

Right now in my current project i have a string like this :
std::string ordre="0x010x030x000x320x000x01";
And i would like to create a char array looking like this with it (and if possible the reverse action too) :
unsigned char Com[]= {0x01, 0x03, 0x00, 0x32, 0x00, 0x01};
I have no problem working with the string, creating another std::string and getting the 0x01 part in the beginning using ordre.at() for the characters i want. But i can't find a way to put this new string 0x01 into Com[1].
Writing directly :
Com[1]=0x01;
It works but i would like to make something where Com[1] could change.
Right now in my current project i have a string like this :
std::string ordre="0x010x030x000x320x000x01";
And i would like to create a char array looking like this with it (and if possible the reverse action too) :
unsigned char Com[]= {0x01, 0x03, 0x00, 0x32, 0x00, 0x01};
First, "0x01" is different than 0x01. To extract values from the string, you will need to read it in a loop, four characters at a time:
if(ordre.size() % 4)
throw std::runtime_error{ "invalid string length; format is different" };
std::vector<int> values;
auto b = std::begin(ordre);
const auto e = std::end(ordre);
while(b != e)
{
std::string s{ b, b+4 };
values.push_back(std::stoi(s, 0, 16));
b += 4;
}
If you use C++ : use STL structures instead of (strugling with) arrays
If I where you i'll build a std::vector<unsigned char> and fill it dynamically by iterating over the x in the loop.
I would do the vector filling as such:
Note: This code work ith any size input and is not limited to 4 chars substrings. It is therefore more general but less efficient then the other answers code. Choose according to your needs
std::string order = "0x010x020x030x2360x10240x9001";
std::vector<int> coms;
size_t pos = 0, it;
while ((it = order.find("0x", pos + 1)) != std::string::npos)
{
coms.push_back(std::stoi(order.substr(pos, it-pos), 0, 16));
pos = it;
}
coms.push_back(std::stoi(order.substr(pos), 0, 16));
gives:
0x01 = 1
0x02 = 2
0x03 = 3
0x236 = 556
0x1024 = 4132
0x9001 = 36865