How to Convert Byte Array to Char in C++ - c++

I don't know how to write a code that convert a byte array to a char array in C++ (using an Arduino board) and publish mqtt. I tried to search but I don't understand.
Example
byte Code[3] = {0x00 ,0x01 , 0x83};
char byteTochar[3];
for (int i = 0; i <= 2; i++) {
Serial.printf("%d", Code[i]);
Serial.println();
client.publish("publish/data", byteTochar[i]);
}
Error message
converting to 'String' form initializer list would use explicit constructor 'String::String'(unsigned char, unsigned char)'

Its actually do c, ArduinoPlayGround http://playground.arduino.cc/Main/Printf.
However, you can just use casting for each element:
char h = (char)Code[i];

Related

Adding hexadecimal to string

I'm trying to add a single 1 bit to a string, however, it seems that I keep getting the char converted to an int. I've tried typecasting it to an unsigned char, but I think that it's still converting it.
string output = "abc";
output += 0x80;
for (char c : output) printf("%02x", c);
I keep getting 616263ffffff80. However, I'm trying to get it to be 61626380;
The problem is your printf. It's using %x which expects a unsigned int value. However, your c value is signed char. And so this value is converted to the equivalent integer which happens to be 0xffffff80.
You can correct this in various ways:
Use unsigned value for your loop variable:
for (unsigned char c : output) printf("%02x", c);
Cast the value to unsigned char:
for (char c : output) printf("%02x", (unsigned char)c);
Use the appropriate format length modifier:
for (char c : output) printf("%02hhx", c);

convert uint_8 ascii to string

I am sending a string from RaspberryPi to ESP32 via BT.I am getting an ascii values one per line. How to convert it into a whole one String? I tried as follow but I get an error while running the method printReceivedMEssage(buffer):
invalid conversion from 'uint8_t {aka unsigned char}' to 'uint8_t* {aka unsigned char*}' [-fpermissive]
uint8_t buffer;
void printReceivedMessage(const uint8_t* buf) {
char string_var[100];
size_t bufflen = sizeof(buf);
for (int i = 0; i < bufflen; ++i) {
Serial.println(static_cast<char>(buf[i]));
}
memcpy( string_var, buf, bufflen );
string_var[bufflen] = '\0'; // 'str' is now a string
Serial.print("string_var=");
Serial.println(string_var);
}
void loop()
{
buffer = (char)SerialBT.read();
Serial.println(buffer); // THIS SHOWS AN ASCII VALUES ONE PER LINE
printReceivedMessage(buffer); // ERROR
delay(1000);
}
One error that should be fixed is the incorrect sizeof(). The code is getting the size of a pointer, which in C and C++ does simply that (you will get the value 4 for 32-bit pointers for example), but doesn't return the size of any "contents" being pointed to. In your case, where the buffer contains a null-terminated string, you can use strlen()
size_t bufflen = strlen(buf);
To remove the compiler error you need to pass a byte array to printReceivedMessage(). For example:
uint8_t buffer[200];
Also, you could print the buffer in one call with Serial.println(a_string), but then you need to read a whole string with SerialBT.readString().
The byte array seems to be an unnecessary intermediary. Just read a String over BT, and print it, as in the post I linked to.
Serial.println(SerialBT.readString());

Subsetting char array without copying it in C++

I have a long array of char (coming from a raster file via GDAL), all composed of 0 and 1. To compact the data, I want to convert it to an array of bits (thus dividing the size by 8), 4 bytes at a time, writing the result to a different file. This is what I have come up with by now:
uint32_t bytes2bits(char b[33]) {
b[32] = 0;
return strtoul(b,0,2);
}
const char data[36] = "00000000000000000000000010000000101"; // 101 is to be ignored
char word[33];
strncpy(word,data,32);
uint32_t byte = bytes2bits(word);
printf("Data: %d\n",byte); // 128
The code is working, and the result is going to be written in a separate file. What I'd like to know is: can I do that without copying the characters to a new array?
EDIT: I'm using a const variable here just to make a minimal, reproducible example. In my program it's a char *, which is continually changing value inside a loop.
Yes, you can, as long as you can modify the source string (in your example code you can't because it is a constant, but I assume in reality you have the string in writable memory):
uint32_t bytes2bits(const char* b) {
return strtoul(b,0,2);
}
void compress (char* data) {
// You would need to make sure that the `data` argument always has
// at least 33 characters in length (the null terminator at the end
// of the original string counts)
char temp = data[32];
data[32] = 0;
uint32_t byte = bytes2bits(data);
data[32] = temp;
printf("Data: %d\n",byte); // 128
}
In this example by using char* as a buffer to store that long data there is not necessary to copy all parts into a temporary buffer to convert it to a long.
Just use a variable to step through the buffer by each 32 byte length period, but after the 32th byte there needs the 0 termination byte.
So your code would look like:
uint32_t bytes2bits(const char* b) {
return strtoul(b,0,2);
}
void compress (char* data) {
int dataLen = strlen(data);
int periodLen = 32;
char* periodStr;
char tmp;
int periodPos = periodLen+1;
uint32_t byte;
periodStr = data[0];
while(periodPos < dataLen)
{
tmp = data[periodPos];
data[periodPos] = 0;
byte = bytes2bits(periodStr);
printf("Data: %d\n",byte); // 128
data[periodPos] = tmp;
periodStr = data[periodPos];
periodPos += periodLen;
}
if(periodPos - periodLen <= dataLen)
{
byte = bytes2bits(periodStr);
printf("Data: %d\n",byte); // 128
}
}
Please than be careful to the last period, which could be smaller than 32 bytes.
const char data[36]
You are in violation of your contract with the compiler if you declare something as const and then modify it.
Generally speaking, the compiler won't let you modify it...so to even try to do so with a const declaration you'd have to cast it (but don't)
char *sneaky_ptr = (char*)data;
sneaky_ptr[0] = 'U'; /* the U is for "undefined behavior" */
See: Can we change the value of an object defined with const through pointers?
So if you wanted to do this, you'd have to be sure the data was legitimately non-const.
The right way to do this in modern C++ is by using std::string to hold your string and std::string_view to process parts of that string without copying it.
You can using string_view with that char array you have though. It's common to use it to modernize the classical null-terminated string const char*.

Convert (comma separated hex) String to unsigned char array in Arduino

The response payload of my http request looks like this (but can be modified to any string best suitable for the task):
"{0X00,0X01,0XC8,0X00,0XC8,0X00,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,}"
How do I turn it into an unsigned char array containing the hex values like this:
unsigned char gImage_test[14] = { 0X00,0X01,0XC8,0X00,0XC8,0X00,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,}
Additional information: The length of the payload string is known in advance and always the same. Some partial solution I found can't be directly applied due to the limitations of the wrapper nature of Arduino for c++. Looking for a simple solution within the Arduino IDE.
Use sscanf("%x", ...), here an example of just 3 hex numbers:
const char *buffer = "{0X00,0X01,0XC8}";
unsigned int data[3];
int read_count = sscanf(buffer, "{%x,%x,%x}", data, data+1, data+2);
// if successful read_count will be 3
If using sscanf() (#include <stdio.h>) is within your limitations then you can call with it "%hhx" to extract each individual hex value into an unsigned char like this:
const int PAYLOAD_LENGTH = 14; // Known in advance
unsigned char gImage_test[PAYLOAD_LENGTH];
#include <stdio.h>
int main()
{
const char* bufferPtr = "{0X00,0X01,0XC8,0X00,0XC8,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF}";
for (int i = 0; i < PAYLOAD_LENGTH && sscanf(bufferPtr + 1, "%hhx", &gImage_test[i]); i++, bufferPtr += 5);
return 0;
}

Converting a unsigned char(BYTE) array to const t_wchar* (LPCWSTR)

Alright so I have a BYTE array that I need to ultimately convert into a LPCWSTR or const WCHAR* to use in a built in function. I have been able to print out the BYTE array with printf but now that I need to convert it into a string I am having problems... mainly that I have no idea how to convert something like this into a non array type.
BYTE ba[0x10];
for(int i = 0; i < 0x10; i++)
{
printf("%02X", ba[i]); // Outputs: F1BD2CC7F2361159578EE22305827ECF
}
So I need to have this same thing basically but instead of printing the array I need it transformed into a LPCWSTR or WCHAR or even a string. The main problem I am having is converting the array into a non array form.
LPCWSTR represents a UTF-16 encoded string. The array contents you have shown are outside the 7bit ASCII range, so unless the BYTE array is already encoded in UTF-16 (the array you showed is not, but if it were, you could just use a simple type-cast), you will need to do a conversion to UTF-16. You need to know the particular encoding of the array before you can do that conversion, such as with the Win32 API MultiByteToWideChar() function, or third-party libraries like iconv or ICU, or built-in locale convertors in C++11, etc. So what is the actual encoding of the array, and where is the array data coming from? It is not UTF-8, for instance, so it has to be something else.
Alright I got it working. Now I can convert the BYTE array to a char* var. Thanks for the help guys but the formatting wasn't a large problem in this instance. I appreciate the help though, its always nice to have some extra input.
// Helper function to convert
Char2Hex(unsigned char ch, char* szHex)
{
unsigned char byte[2];
byte[0] = ch/16;
byte[1] = ch%16;
for(int i = 0; i < 2; i++)
{
if(byte[i] >= 0 && byte[i] <= 9)
{
szHex[i] = '0' + byte[i];
}
else
szHex[i] = 'A' + byte[i] - 10;
}
szHex[2] = 0;
}
// Function used throughout code to convert
CharStr2HexStr(unsigned char const* pucCharStr, char* pszHexStr, int iSize)
{
int i;
char szHex[3];
pszHexStr[0] = 0;
for(i = 0; i < iSize; i++)
{
Char2Hex(pucCharStr[i], szHex);
strcat(pszHexStr, szHex);
}
}