I am coming back to C++ after many years (and never went so deeply before), so please indulge with me for my noobness :)
I have, as a field of a struct, a *void which points to some data. The memory pointed by the struct is filled with different data after every call of a given function, so I'd like to "cache" the results after every function call in a vector, in order to obtain all data in the end. How can I achieve this goal?
I declared a static vector<unsigned char> vectorBuffer; and tried vectorBuffer.insert(vectorBuffer.end(), (unsigned char*)myStruct->thePointer) and vectorBuffer.push_back((unsigned char*)myStruct->thePointer) but obviously I'm getting errors. Which is the correct way to obtain such a result?
Thanks
EDIT: I know the size of the void* as well, since I have another field in my struct that refreshes as the data do.
Something along these lines is what you want to do to buffer the data fragmented over multiple callbacks:
#include <vector>
std::vector<char> buffer;
buffer.insert(buffer.end(), data, data+length);
Assuming that data is your data coming in the callback and length is available too.
You should declare the vector with
static vector<unsigned char *> vectorBuffer;
(it's an array of unsigned character pointers, not unsigned characters).
To save the data (assuming you know the size),
unsigned char *p = new unsigned char[myStruct->bufferLength];
memcpy((void *) p, myStruct->thePointer, myStruct->bufferLength);
vectorBuffer.push_back(p);
You can then keep track of the length with
static vector<unsigned char *> bufferLength;
bufferLength.push_back(myStruct->bufferLength);
Note that you will need to free the memory afterwards.
Related
I'm trying to do the simplest thing here. I want to create a method that will take in a byte (char) array, inflate it using miniz tinfl_decompress method and then return a byte array containing the inflated data.
First things first. The arrays given will never be bigger than 100kB, vast majority will be smaller than 50k. Hence, I don't think I need to use any kind of buffer for it. Anyway, this is what I've got:
std::vector<unsigned char> unzip(std::vector<unsigned char> data)
{
unsigned char *outBuffer = new unsigned char[1024 * 1024];
tinfl_decompressor inflator;
tinfl_status status;
tinfl_init(&inflator);
size_t inBytes = data.size() - 9;
size_t outBytes = 1024 * 1024;
status = tinfl_decompress(&inflator, (const mz_uint8 *)&data[9], &inBytes, outBuffer, (mz_uint8 *)outBuffer, &outBytes, 0);
return ???
}
I know the output I want begins at memory location &outBuffer, but I don't know how long it is (I do happen to know it will be less than 1MB), so I cannot pack it into a vector and send it on it's way. I had hoped that outBytes would hold the size of the output, but they are set to 1 after the decompression. I know that decompression didn't fail, since status returned is TINFL_STATUS_DONE (0).
Is this even the right way of doing it? This is a method that will be called a lot in my program, so I want something that is as fast as possible.
How do I get the vector out of it? Should I use a different data type? An array (the [] type)? The decompressed data will be read sequentially only once, after what it will be discarded.
EDIT:
It seems that the file I was trying to decompress was not of the proper format; it was zip, this takes zlib.
Caveat: Totally untested code.
It should go something like exchange
unsigned char *outBuffer = new unsigned char[1024 * 1024];
for
std::vector<unsigned char> outBuffer(1024 * 1024);
to get a vector. Then call tinfl_decompress using the data method to get the vector's underlying buffer. It should look something like
status = tinfl_decompress(&inflator,
(const mz_uint8 *)&data[9],
&inBytes,
(mz_uint8 *)outBuffer.data(),
(mz_uint8 *)outBuffer.data(),
&outBytes,
0);
And then resize the vector to the number of bytes stored in the vector for convenience later.
outBuffer.resize(outBytes);
Note the vector will NOT be resized down. It will still have a capacity of 1 MiB. If this is a problem, an additional call to std::vector::shrink_to_fit is required.
Finally
return outBuffer;
const char *RecBuffer, int *packetLength point to the data and the size
string packet(RecBuffer,*packetLength);//store here
...do some stuff
RecBuffer = packet.c_str();//retrieve it later
now what is happening is that my Recbuffer contains lots of floats, and ints packet together which I receive as a UDP packet. But when I store and retrieve it from the string it contains garbage.
Where am I going wrong?
I suspect the std::string instance named packet is being destructed, or modified, before RecBuffer is being used, meaning RecBuffer is a dangling pointer. You need to copy the content of packet rather than store a reference to an internal member of it. Instead of dynamically allocating a char* suggest using a std::vector<char> (as commented by Bartek) instead:
std::vector<char> RecBuffer(packet.begin(), packet.end());
Use &RecBuffer[0] (or RecBuffer.data() if available, introduced in c++11) to access the internal array.
Use memcpy:
RecBuffer[packet.size()]=0;
memcpy(RecBuffer, packet.c_str(), packet.size());
I'm reading multiple reports from a HID device into an unsigned char, then trying to copy the data to a std::vector. I'm also writing the data out to a file for hex analysis, whose content appears to be correct when I view it. However, the std::vector doesn't appear to contain the correct data when I dump it to the console.
This is the code:
typedef vector<unsigned char> buffer_t;
buffer_t sendCommand (hid_device *devh, const unsigned char cmd[], int reports) {
unsigned char outbuf[0x40];
buffer_t retbuf(0x40 * reports);
hid_write(devh, cmd, 0x41);
int i;
FILE *file = fopen("test.out", "w+b");
while (i++ < reports) {
hid_read(devh, outbuf, 0x40);
fwrite(outbuf, 1, sizeof(outbuf), file);
retbuf.push_back(*outbuf);
}
fclose(file);
cout << &retbuf[0];
return retbuf;
}
I have a feeling I'm way off the mark here; I'm fairly new to C/C++, and I've been stuck with this for a while now. Can anyone tell me what I'm doing wrong, or point me in a better direction?
You want to add multiple unsigned char objects to your vector, but push_back only adds one.
So, replace retbuf.push_back(*outbuf); with either:
for (size_t i = 0; i < sizeof(outbuf); ++i) {
retbuf.push_back(outbuf[i]);
}
or
std::copy(outbuf, outbuf+sizeof(outbuf), std::back_inserter(retbuf));
or
retbuf.insert(retbuf.end(), outbuf, outbuf+sizeof(outbuf));
which all do the same thing.
You create your vector with a certain size:
buffer_t retbuf(0x40 * reports);
but push_back increases the size of the vector by adding an element at the end. You should create it empty:
buffer_t retbuf;
Optionally, you could arrange for the vector to have enough space allocated, ready for the elements you're going to add:
retbuf.reserve(0x40 * reports);
This is purely a performance issue, but sometimes it's a significant issue for large vectors, or vectors of types that (unlike unsigned char) are expensive to copy/move when the vector runs out of internal space and has to allocate more.
A note on style: you repeat the literal value 0x40 a few times, and also use sizeof(outbuf). It's often best to define a constant, and use the name throughout:
const int report_size = 0x40;
This is partly in case the number changes in future, but also it's about the readability of your code -- if someone sees 0x40 they may or may not immediately understand why that is the correct value. If someone sees report_size then they don't know what value that actually is until they look it up, but they do know why you're using that value.
The problem is in this line: buffer_t retbuf(0x40 * reports); It means that you create vector with 0x40 * reports elements filled with default value for unsigned char (zero). Then push_back() just adds new elements to the end of vector and doesn't affect existing elements.
You need to rewrite it this way:
buffer_t retbuf; // Empty vector
retbuf.reserve(0x40 * reports); // Preallocate memory for known element count
This way push_back() will work as expected and add elements to empty vector from beginning.
And of course you shall push_back() all elements of outbuf, not only first one (*outbuf).
To push back multiple values use std::vector's function assign. For example:
std::vector<char>vec1;
char array[3] = {'a', 'b', 'c'};
vec1.assign(array, array+3);
I am currently working on a project were I had to do this.
Your vector is of a type unsigned char, which means every element of it is of this type. Your outbuf is an array of unsigned chars.
The push_back() only appends one item to the end of the vector, so push_back(*outbuf) will only add the first element of the outbuf to the vector, not all of them.
To put all the data into the vector, you will need to push_back them one-by-one, or use std::copy.
Note that since outbuf is a char array, then *outbuf will be the first element of the char array because of the array/pointer duality.
I think you probably wanted to do:
typedef vector<string> buffer_t; // alternatively vector<unsigned char*>
...
retbuf.push_back(outbuf);
...
Or
typedef vector<unsigned char> buffer_t;
...
for (size_t i = 0; i < sizeof(outbuf); i++)
retbuf.push_back(outbuf);
...
I need to save packet state for a while.
So I read the packet data which is represented as unsigned char* and than I create a record with this data and save the record in the list for a while.
Which will be a better way to represent the packet in the record as char* or as char[].
How do i copy the read data ( unsigned char ) to both options :
To unsigned char[] and to unsigned char*
I need to copy the data because each time I read packet it will be readed to the same char*,so when I save it for a while I need to copy data first
If the packet data is binary I'd prefer using std::vector to store the data, as opposed to one of the C strXXX functions, to avoid issues with a potential NULL character existing in the data stream. Most strXXX functions look for NULL characters and truncate their operation. Since the data is not a string, I'd also avoid std::string for this task.
std::vector<unsigned char> v( buf, buf + datalen );
The vector constructor will copy all the data from buf[0] to buf[datalen - 1] and will deallocate the memory when the vector goes out of scope. You can get a pointer to the underlying buffer using v.data() or &v[0].
So, it sounds like you need to save the data from multiple packets in a list until some point in the future.
If it was me, I'd use std::string or std::vector normally because that removes allocation issues and is generally plenty fast.
If you do intend to use char* or char[], then you'd want to use char*. Declaring a variable like "char buf[1024];" allocates it on the stack, which means that when that function returns it goes away. To save it in a list, you'd need to dynamically allocate it, so you would do something like "char *buf = new char[packet.size];" and then copy the data and store the pointer and the length of the data in your list (or, as I said before, use std::string which avoids keeping the length separately).
How do you copy the data?
Probably memcpy. The strcpy function would have problems with data which can have nul characters in it, which is common in networking situations. So, something like:
char *buf = new char[packet_length];
memcpy(buf, packet_data, packet_length);
// Put buf and packet_length into a structure in your list.
I have a (void*) buffer that I need to convert to std::vector<unsigned char> before I can pass it on. Unfortunately, my C++ casting skills a little weak. Any suggestions?
You will need the length of the buffer. Once you do, we can do this:
unsigned char *charBuf = (unsigned char*)voidBuf;
/* create a vector by copying out the contents of charBuf */
std::vector<unsigned char> v(charBuf, charBuf + len);
Okay, the comment got me started on why I did not use reinterpret_cast:
In C++, the C-style cast is a convenience function -- it asks the compiler to choose the safest and most portable form of conversion over the set of available cast operators.
The reinterpret_cast is implementation defined and should always be the last thing on your mind (and used when you are necessarily doing a non-portable thing knowingly).
The conversion between (unsigned doesn't change the type) char * and void * is portable (you could actually use static_cast if you are really picky).
The problem with the C-style cast is: the added flexibility can cause heartaches when the pointer type changes.
Note: I agree with the general convention of not casting as much as possible. However, without any source provided, this is the best I could do.
You can't simply cast a void* to a std::vector<unsigned char> because the memory layout of the latter includes other objects, such as the size and the number of bytes currently allocated.
Assuming the buffer is pointed to by buf and its length is n:
vector<unsigned char> vuc(static_cast<char*>(buf), static_cast<char*>(buf) + n);
will create a copy of the buffer that you can safely use.
[EDIT: Added static_cast<char*>, which is needed for pointer arithmetic.]
The only time this would be legitimate is if you had already created a vector, and simply wanted to get it back.
void SomeFunc(void* input);
main() {
std::vector< unsigned char > v;
SomeFunc((void*) &v);
}
SomeFunc(void* input) {
// Now, you could cast that void* into a vector
std::vector< unsigned char >* v_ = (vector<unsigned char>*)input
}
I haven't actually tried to see if this will run, but that's the spirit of it. That said, if you are making this from scratch, you are definitely doing it wrong. This is really bad. The only time this could be even remotely understandable is if you are forced to implement the already defined "SomeFunc()".
using std::vector class for an already allocated buffer is not a solution. A std::vector object manages the memory and deallocates it at destruction time.
A complicated solution might be to write your own allocator, that uses an already allocated buffer, but you have to be very careful on several scenarios, like vector resizing, etc.
If you have that void* buffer bound through some C API functions, then you can forget about conversion to std::vector.
If you need only a copy of that buffer, it can be done like this:
std::vector< unsigned char> cpy(
(unsigned char*)buffer, (unsigned char*)buffer + bufferSize);
where bufferSize is the size in chars of the copied buffer.