What is happening in this code? reinterpret_cast<int*>(buf) - c++

It seems to me that the buffer is being modified. Does it put 6 integers and then 5 floats into the buffer? It's also strange that they set size to 44 instead of 1024*sizeof(char). Perhaps the whole buffer is passed to write() but write() writes only the first 44 bytes to the client.
Could you please explain line by line? I have no experience with c++.
char buf[1024];
int* pInt = reinterpret_cast<int*>(buf);
*pInt = 5;
*(pInt+1) = 2;
*(pInt+2) = 3;
*(pInt+3) = 4;
*(pInt+4) = 5;
*(pInt+5) = 6;
float* pFloat = reinterpret_cast<float*>(pInt+6);
*pFloat = 111;
*(pFloat+1) = 222;
*(pFloat+2) = 333;
*(pFloat+3) = 444;
*(pFloat+4) = 555;
int n;
int size = (1+2*5)*4;
n = write(buf, size);

Does it put 6 integers and then 5 floats into the buffer?
Yes.
It's also strange that they set size to 11 instead of 1024*sizeof(char)
They don't want to write the entire buffer. Thy want to write just the ints and floats that were written to the buffer.
FWIW, that is poorly written code. It assumes that sizeof(int) and sizeof(float) are both equal to 4. A more portable method would use:
int size = 6*sizeof(int) + 5*sizeof(float);
Caution
Even though the posted code might work under some, perhaps most, circumstances, use of
int* pInt = reinterpret_cast<int*>(buf);
*pInt = 5;
is cause for undefined behavior by the standard. It violates the strict aliasing rule. There wasn't an int to begin with at that location.
Had you used:
int array[5] = {};
char* cp = reinterpret_cast<char*>(array);
// ...
int* iptr = reinterpret_cast<int*>(cp);
*iptr = 10;
there would be no problem since cp points to a place where an int was there to begin with.
For your use case, it will be better to use:
char buf[1024];
int intArray[] = {5, 2, 3, 4, 5, 6};
std::memcpy(buff, intArray, sizeof(intArray));
float floatArray = {111, 222, 333, 444, 555};
std::memcpy(buff+sizeof(intArray), floatArray, sizeof(floatArray));
int n;
int size = sizeof(intArray) + sizeof(floatArray);
n = write(buf, size);
Further reading:
reinterpret_cast creating a trivially default-constructible object
Unions and type-punning

Related

Dump Lora.read() to array

I want to dump chars from a Lora transmitter using Arduino Nano. With this line I assume it can be store the chars into an array:
char* dump = (char)LoRa.read();
char in[255];
strcpy(in, dump);
char str[] = in;
But unfortunately I get this compiler error:
exit status 1
initializer fails to determine size of 'str'
How I fix it?
UPDATE
I give my entire code. I used shox96 shox96 from siara-cc for my objective to compress the data from Lora.read().
void print_compressed(char *in, int len) {
int l;
byte bit;
//Serial.write("\nCompressed bits:");
for (l=0; l<len*8; l++) {
bit = (in[l/8]>>(7-l%8))&0x01;
//Serial.print((int)bit);
//if (l%8 == 7) Serial.print(" ");
}
}
void loop() {
char* dump = (char)LoRa.read();
char in[255];
strcpy(in, dump);
char str[] = in;
char cbuf[300];
char dbuf[300];
int len = sizeof(str);
if (len > 0) {
memset(cbuf, 0, sizeof(cbuf));
int ctot = shox96_0_2_compress(str, len, cbuf, NULL);
print_compressed(cbuf, ctot);
memset(dbuf, 0, sizeof(dbuf));
int dlen = shox96_0_2_decompress(cbuf, ctot, dbuf, NULL);
dbuf[dlen] = 0;
float perc = (dlen-ctot);
perc /= dlen;
perc *= 100;
Serial.print(ctot);
Serial.write(",");
Serial.println(dlen);
}
delay(1000);
}
The compiler can only supply the size of an array for you on creation if it has a brace enclosed initializer list. Like this:
int array[] = {1, 2, 3, 4, 5};
If you're doing anything other than that then you need to put a number inside those braces. Since you're making a copy of the array in and that array is 255 char then this one needs to be 255 char as well in order to accommodate.
char str[255] = in;
My comment on your question still stands though. This answer clears your compiler error, but I don't think it is really a solution to your larger problem. But without seeing more of your code and knowing more about it I can't tell much about it. You already have two copies of this data by the time you get to that line. I'm not sure why you think you need to have a third.

How to idiomatically convert ``char*`` to ``double*``

I'm relearning C++, and I'm trying to work with boost::iostreams::mapped_file. This class maps file data to char*, I'd like to cast it to double* (since I'm working with doubles).
I could cast it using C-style cast: double* foo = (double*) data, but I'm trying go use idiomatic C++, and C++ favours C++ casts like: static_cast and so on.
I came up with:
double* data = static_cast<double*>((void*)file.data());
(file->data returns char*).
Which really isnt cleaner.
Here is what I'm trying to do (this code works!):
BOOST_AUTO_TEST_CASE(OpenMMapArray){
typedef boost::multi_array_ref<double, 3> arrayd3;
typedef std::array<size_t, 3> index3d;
index3d shape = {{ 20, 20, 20 }};
size_t size = sizeof(double)*std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>());
boost::iostreams::mapped_file file;
boost::iostreams::mapped_file_params params;
params.path = "/tmp/mmaptest-2";
params.mode = std::ios::in | std::ios::out;
params.new_file_size = size;
file.open(params);
double* data = static_cast<double*>((void*)file.data());
arrayd3 array(data, shape);
array[0][0][0] = 20;
array[0][1][0] = 19;
array[1][0][0] = 18;
array[0][0][5] = 17;
BOOST_CHECK(data[0] == 20);
BOOST_CHECK(data[20] == 19);
BOOST_CHECK(data[20*20] == 18);
BOOST_CHECK(data[5] == 17);
file.close();
}
In this particular case, you actually are trying to re-interpret the data as a different type. So a reinterpret_cast is in order:
double* data = reinterpret_cast<double*>(file.data());

Casting pointer to Array (int* to int[2])

How do I cast or convert an int* into an int[x]?
First, I know that pointers can be indexed. So I know that I can loop through the pointer and array and manually convert the pointer. (eg. a for loop with arr[i] = p[i]). I want to know if the same result can be achieved in fewer lines of code.
As an example I tried to cast pointer int* c = new int[x] to an array int b[2]
int a = 1;
int b[2] = { 2, 3 };
int* c = new int[b[1]];
c[0] = b[0];
c[1] = b[1];
c[2] = a;
I wanted to see what values were where, so I made a simple program to output addresses and values. The output is just below:
Address of {type: int} &a = 0031FEF4; a = 1
Address of {type: int[2]} &b = 0031FEE4; b = 0031FEE4
Address of {type: int[2]} &b[0] = 0031FEE4; b[0] = 2
Address of {type: int[2]} &b[1] = 0031FEE8; b[1] = 3
Address of {type: int*} &c = 0031FED8; c = 008428C8
Address of {type: int*} &c[0] = 008428C8; c[0] = 2
Address of {type: int*} &c[2] = 008428D0; c[2] = 1
Once I made sure I knew what was where I tried a few things. The first idea that came to mind was to get the address of the second element to the pointer's allocation, then replace the array's memory address with it (see the code just below). Everything I did try ultimately failed, usually with syntax errors.
This is what I tried. I really want this to work, since it would be the simplest solution.
b = &c[1];
This did not work obviously.
Edit: Solution:
Don't do it!
If it's necessary create a pointer to an array and then point to the array; this is pointless for any purposes I can fathom.
For more detailed information see the answer by rodrigo below.
First of all b is an array, not a pointer, so it is not assignable.
Also, you cannot cast anything to an array type. You can, however, cast to pointer-to-array.
Note that in C and C++ pointer-to-arrays are rather uncommon. It is almost always better to use plain pointers, or pointer-to-pointers and avoid pointer-to-arrays.
Anyway, what you ask can be done, more or less:
int (*c)[2] = (int(*)[2])new int[2];
But a typedef will make it easier:
typedef int ai[2];
ai *c = (ai*)new int[2];
And to be safe, the delete should be done using the original type:
delete [](int*)c;
Which is nice if you do it just for fun. For real life, it is usually better to use std::vector.
Though you can't reassign an array identifier.. sometimes the spirit of what you're doing allows you to simply create a reference and masquerade yourself as an array. Note: this is just a slight extension of rodrigo's answer... and it is still worth mentioning that there is probably a better way to accomplish whatever the task is.
#include <iostream>
int main() {
int x[1000] = {0};
for(int i = 0; i < 10; ++i) {
int (&sub_x)[100] = *(int(*)[100])(&x[i*100]);
//going right to left basically:
// 1. x[i*100] -- we take an element of x
// 2. &x[N] -- we take the address
// 3. (int(*)[100]) -- we cast it to a pointer to int[100]
// 4. *(...) -- lastly we dereference the pointer to get an lvalue
// 5. int (&sub_x)[100] -- we create the reference `sub_x` of type int[100]
for(int j = 0; j < 100; ++j) {
sub_x[j] = (i*100)+j;
}
}
for(int i = 0; i < 1000; ++i) {
if(i != 0) {
std::cout << ", ";
}
std::cout << x[i];
}
std::cout << std::endl;
}
As you'd expect the output just ends up printing 0-999 with no gaps
output:
0, 1, 2, ..., 999

Writing data to memory in C++

I want to write a a mix of int, char, real in void *data.
I am using a file pointer to run through the data block.
Now my question is that since the data type is void, I have to typecast it to int while writing integer and char for writing string.
While typecasting I used the following sample code:
*((int *)data+0) = 14; //writing int
*((int *)data+4) = 5; //writing int, left a space of 4 bytes for int
*((char *)data+8) = 'a'; //writing char
*((char *)data+9) = 'f'; //writing char
But then while reading the values back it didnt give the correct value.
cout<<*((int *)data+0);
cout<<*((int *)data+3);
cout<<*((char *)data+8);
Is the way my code is written correct? I am doubtful about it as data is void.
*((int *)data+4) = 5; // writing 4th int
cout<<*((int *)data+3); // but reading third one
And just in case, ((int *)data+4) points to 4th integer (that is, 16th byte given int size = 4), not to 4th byte. That is, you code overwrites bytes 0-3, then 16-19, then 8th, then 9th. What you probably meant is: *(int *)( (char*)data + X )
Edited to correct mistake pointed out by MSalters
Apart from the typo that others have mentioned (data+3 instead of data+4), you also need to change e.g.
*((int *)data+4)
to
*((int *)data+1)
because adding 4 to an int * doesn't add 4 to the address, it adds 4 * sizeof (int).
If you need to write to an offset that is not a multiple of sizeof(int) (say, 7), you need:
*(int *)((char *)data+7)
For this reason, it might be better to make data a char * to start with, so you can just say
*(int *)(data+7)
Use a class or a struct.
Here, pointer arithmetics is misleading you. When you add 4 to an int * you are adding actually four times sizeof int.
If your data has a constant layout, why don't you just use a struct such as
struct MemoryLayout {
int _first;
int _second;
char _c1;
char _c2;
};
?
You're writing the second one with:
*((int *)data+4) = 5; // offset = 4
and reading it back with:
cout<<*((int *)data+3); // offset = 3
In addition, the (int*) cast is binding to data, not data+4 so that your 4 is scaled up by the size of an int.
If you really want to do this (and a struct is not a possibility due to variances in the data formats), you should cast data to a char*, then add the number of bytes to get the char offset, then cast that to your desired type.
That would be something like:
*((int*)((char*)(data + 0)) = 14; //writing int
*((int*)((char*)(data + 4)) = 5; //writing int
*((char*)data + 8) = 'a'; //writing char
*((char*)data + 9) = 'f'; //writing char
int Data;
//char Data;
//float Data;
FILE *File = fopen("File.txt","wb");
fwrite((char *)&Data,sizeof(Data),1,File);
fclose(File);
File = fopen("File.txt","rb");
fread((char *)&Data,sizeof(Data),1,File);
fclose(File);
...
int DataInt1 = 200;
char DataChar1 = 'N';
FILE *File = fopen("File.txt","wb");
fwrite((char *)&DataInt1,sizeof(DataInt1),1,File);
fwrite((char *)&DataChar1,sizeof(DataChar1),1,File);
fclose(File);
int DataInt2 = 0;
char DataChar2 = 0;
File = fopen("File.txt","rb");
fread((char *)&DataInt2,sizeof(DataInt2),1,File);
fread((char *)&DataChar2,sizeof(DataChar2),1,File);
fclose(File);
printf("%d %d!\n",DataInt2,DataChar2);

Working with Arrays in C

I am new to C and C++ and I need help with arrays. I have an array initialized to zero with 500 elements(myDataBinary). Now I have one more array ith values in it say 1,2,3....Now by reading the values (1,2,3...) from(my_data[10]) i want to make the corresponding elements in myDataBinary "1" and rest should be "0". I have written the below code to achieve this, but I am getting some segmentation fault and not able to see the proper results. Any help on this would be appreciated. Thanks in advance
int my_data[10] = {1,3,9,10};
int myDataBinary[500] = {0};
int index;
for(int i=0; i<sizeof(my_data);i++)
{
index = my_data[i];
myDataBinary[index] = 1;
printf("rec data %d = %d\n",index,myDataBinary[index]);
}
sizeof(my_data) returns the total size of the array in bytes, not the number of elements.
Since ints are (usually) 2 bytes wide, you're ending up outside the array.
Replace sizeof(my_data) in the for loop with sizeof(my_data)/sizeof(int) and try again.
sizeof operator gives the size of an object (or type) in bytes. The canonical way to determine the number of elements in an array x is:
sizeof x / sizeof x[0]
This does not depend upon knowing the type of the elements of x, and will work even if you change it. sizeof my_data / sizeof(int) doesn't have that property.
Note that my_data has to be an array, it cannot be a pointer. This is important because in many contexts (when passed to a function for example), the name of an array decays to a pointer, so the following "won't work":
void f(int *data)
{
printf("%zu\n", sizeof data);
}
int main(void)
{
int my_data[10] = {1,3,9,10};
printf("%zu\n", sizeof my_data);
f(my_data);
return 0;
}
The above program will print two different values (unless sizeof(int)*10 == sizeof(int *)).
Don't use sizeof(my_data) - this doesn't give you what you want. To find the number of the elements you can do int n = sizeof(my_data) / sizeof(int):
int my_data[10] = {1,3,9,10};
int myDataBinary[500] = {0};
int index;
int n = sizeof(my_data) / sizeof(int);
for(int i=0; i<n;i++)
{
index = my_data[i];
myDataBinary[index] = 1;
printf("rec data %d = %d\n",index,myDataBinary[index]);
}