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);
...
Related
I'm trying to fill a vector with integers from an array I have but when I check the contents of the vector all the values are zero.
I'm using vector.push_back() to try and fill the vector so it will be in the same order as the array as I needed it ordered in a specific way.
unsigned char* buffer = new unsigned char[size];
std::vector<unsigned char> *data = new std::vector<unsigned char>(size);
fread(buffer, sizeof(unsigned char), size, f);
for(int transfer = 0; transfer < size; transfer += 1){
std::cout << buffer[transfer];
data->push_back(buffer[transfer]);
std::cout << int(data->at(transfer));
}
fclose(f);
When I print the output I can see that the values aren't zero when they're coming from the buffer array but they are when I read from the data vector. Here is some example output φ0$0.
std::vector has a constructor for this purpose:
std::vector<unsigned char> data(buffer, buffer + size);
newing a vector almost always should be avoided.
Live
The overload of the constructor of std::vector that you are using takes the number of elements to initialize the vector with and initializes these (to 0 in this case).
After the line
std::vector<unsigned char> *data = new std::vector<unsigned char>(size);
*data therefore contains already size elements set to zero.
Then with data->push_back(...) you are adding additional elements after these size elements. You are not overwriting the previous ones.
Either use
std::vector<unsigned char> *data = new std::vector<unsigned char>();
to default-initialize an empty vector, or use
(*data)[transfer] = ...
to set the elements at the given location.
Furthermore your program has undefined behavior if the fread reads less than size bytes into the array. You need to check the number of bytes read from its return value and you are not allowed to access any elements beyond that in data, because you never initialized it.
You can initialize it to zero with:
unsigned char* buffer = new unsigned char[size]{};
If you want to write C++, don't use C library functions like fread, use the facilities provided by <fstream>, i.e. std::ifstream and std::ofstream instead.
Similarly there is no need for dynamic memory allocation here. Declare variables with automatic storage:
unsigned char buffer[size]{};
std::vector<unsigned char> data(size);
and the rest of the syntax also simplifies:
data[transfer] = ...
Finally, as mentioned in the other answer, there is a constructor for std::vector that will perform the whole copy loop for you. Note however that my argument about undefined behavior still applies when using that.
Defining data as automatic array as in
unsigned char buffer[size]{};
works only if size is a compile-time constant. If it is not, then this part of my advice does not apply. However there is no real need to use arrays at all in any case. You can initialize a std::vector of proper size (compile-time constant or not) and provide that as buffer via its .data() method, which returns a pointer to the underlying (continuous) storage:
std::vector<unsigned char> buffer(size);
fread(buffer.data(), sizeof(unsigned char), buffer.size(), f);
You don't need a separate buffer or any dynamic allocation in your code. You can create the std::vector with the desired size and then read from the file directly into the vector. The std::vector::data member function returns a pointer to the vector's underlying array that you can pass to the fread() function
std::vector<unsigned char> vec(size);
fread(vec.data(), sizeof(unsigned char), size, f);
Ideally you'll also check the return value from fread() to know how many elements were read.
I want to convert size_t to vector of unsigned chars. This vector is defined as 4 bytes.
Could anybody suggest a suitable way to do that?
Once you've reconciled yourself to the fact that your std::vector is probably going to have to be bigger than that - it will need to have sizeof(size_t) elements - one well-defined way is to access the data buffer of such an appropriately sized vector and use ::memcpy:
size_t bar = 0; /*initialise this else the copy code behaviour is undefined*/
std::vector<uint8_t> foo(sizeof(bar)); /*space must be allocated at this point*/
::memcpy(foo.data(), &bar, sizeof(bar));
There is an overload of data() that returns a non-const pointer to the data buffer. I'm exploiting this here. Accessing the data buffer in this way is unusual but other tricks (using unions etc.) often lead to code whose behaviour is, in general, undefined.
By "convert", I'll assume you mean "copy", since vector will allocate and own its memory. You can't just give it a pointer and expect to use your own memory.
An efficient way to do so which avoids two-stage construction (that causes initialization of the array with zero) is to do this:
auto ptr = reinterpret_cast<uint8_t*>(&the_size);
vector<uint8_t> vec{ptr, ptr + sizeof(size_t)};
Note that sizeof(size_t) is not required to be 4. So you shouldn't write your code assuming that it is.
You could write a generic converter using std::bitset
template <typename T>
std::vector<unsigned char> Type_To_Bit_Vector(T type, char true_char, char false_char){
//convert type to bitset
std::bitset<sizeof(type)*8> bset(type);
//convert bitset to vector<unsigned char>
std::vector<char> vec;
for(int i = 0 ; i < bset.size() ; i++){
if (bset[i]){
vec.push_back(true_char);
}else{
vec.push_back(false_char);
}
}
return vec;
}
You could then get a desired vector representation like so:
auto vec = Type_To_Bit_Vector(size_t(123),'1','0');
I have two vectors.
One is
std::vector<unsigned char> one_v;
and the other is
std::vector<bool> outputValuesInBits;
I pushed values to both one_v and outputValuesInBits.
Both vectors have two bytes.
one_v[0] and [1] are filled with data which would be 2 bytes.
outputValuesInBits[0] to [15] are filled with data which would be 2 bytes.
Now, I would like to copy(memcpy) data to char array.
I can successfully copy data from one_v vector as following.
unsigned char* output = new unsigned char[one_v.size()]();
memcpy(&output, one_v.data(), 2);
But I cannot copy data from outputValuesInBits.
If I do as follow,
unsigned char* output = new unsigned char[outputValuesInBits.size()/8+1]();
memcpy(&output, outputValuesInBits.data(), 2);
It gives me an error
error: invalid use of void expression
memcpy(&output, outputValuesInBits.data(), 2);
Can anyone please tell me how I can copy the bool vector to char array?
Thank you in advance!
I'm afraid you cannot in a portable way. Cplusplus page on vector says: The specialization has the same member functions as the unspecialized vector, except data, emplace, and emplace_back, that are not present in this specialization. That means that data in not defined what explains the error when you try to use it.
If portability is not an option, there will be no solution because The storage is not necessarily an array of bool values, but the library implementation may optimize storage so that each value is stored in a single bit. (emphasize mine). My understanding of the may is that you cannot even be sure that the 16 boolean are stored in 2 consecutive bytes: the implementation must only provide you a way to use them (almost) as if they were stored in 16 different booleans.
If you can forget partability, you will have to find the source for you current implementation to know where and how the byte array is stored... but it is not that easy...
std::vector<bool> doesn't have a data member function
At least in g++ compiler you can use the _M_p member of the vector::iterator, which is the pointer to the data.
Example:
std::vector<bool> vBool(16, false);
vBool[0] = true;
vBool[2] = true;
vBool[13] = true;
std::vector<unsigned char> vChar(2);
unsigned short *ptrUS = reinterpret_cast<unsigned short *>( &(vChar[0]) );
*ptrUS = *reinterpret_cast<unsigned short *>(vBool.begin()._M_p);
std::cout << (unsigned int)vChar[0] << " " << (unsigned int)vChar[1] << "\n";
gives in output '5 32', which corresponds to the numbers with 1st and 3rd bit (5) and with the 6th bit (32).
I am fairly new at C++ and am trying to understand how memory manipulation works. I am used to Java and Python and haven't really been exposed to this.
I am working on a project that has the following structure that doesn't quite make sense to me.
typedef struct
{
size_t size;
char *data;
} data_buffer;
This structure basically acts as a buffer, with a pointer to the data stored within the buffer and the size of the buffer to allow the program to know how large the buffer is when reading from it.
An example of how the program uses the buffer:
data_buffer buffer = {0};
//Manipulate data here so it contains pertinent information
CFile oFile;
oFile.Write(buffer.data, buffer.size);
The program mostly uses 3rd party code to read the data found within the buffer, so I am having trouble finding an example of how this is done. My main question is how do I read the contents of the buffer, given only a pointer to a character and a size? However, I would also like to understand how this actually works. From what I understand, memory is written to, with a pointer to where it starts and the size of the memory, so I should be able to just iterate through the memory locations, grabbing each character from memory and tagging it onto whatever structure I choose to use, like a CString or a string. Yet, I don't understand how to iterate through memory. Can someone help me understand this better? Thanks.
There is no reason you cannot use a std::string or CString to manipulate that data. (Use higher level constructs when they are available to you.)
To get the data into a std::string, use the constructor or assignment operator:
std::string s( buffer.data, buffer.size );
You can even stick it in a std::stringstream so you can treat the data buffer like a file:
std::istringstream ss( s );
int n;
ss >> n;
Things work similarly for the MFC string class.
To get the data from a string, you'll need to copy it over. Ideally, you'll be able to allocate the data's memory. Assuming you have data written into a stringstream
std::ostringstream ss;
ss << name << "," << employee_number;
You can then allocate the space you need using the function that creates the data_buffer object:
function_that_creates_a_data_buffer( buffer, ss.str().size() );
If there is no such function (there ought to be!) you must malloc() or new it yourself, as appropriate:
buffer.size = ss.str().size();
buffer.data = (char*)malloc( buffer.size );
Now just copy it:
ss.str().copy( buffer.data, buffer.size );
If your buffer needs a null-terminator (I have so far assumed it doesn't), make sure to add one to the size you allocate and set the last character to zero.
buffer.size = ss.str().size + 1;
buffer.data = new char[ buffer.size ];
ss.str().copy( buffer.data, buffer.size );
buffer.data[ buffer.size-1 ] = 0;
Make sure to look at the documentation for the various classes you will use.
Hope this helps.
A variable of type char* is actually a pointer to memory. Your struct contains data which is of type char* so it is a pointer to memory. (I suggest writing char* data instead of char *data, to help keep this clear.)
So you can use it as a starting point to look at your data. You can use another pointer to walk over the buffer.
char* bufferInspectorPointer;
bufferInspectorPointer = buffer.data;
bufferInspectorPointer will now point to the first byte of the buffer's data and
*bufferInsepectorPointer
will return the contents of the byte.
bufferInspectorPointer++
will advance the pointer to the next byte in the buffer.
You can do arithmetic with pointers in C++, so
bufferInspectorPointer - buffer.data
will tell you how many bytes you have covered. You can compare it to buffer.size to see how far you have left to go.
Since you tagged this as C++ I'd recommend using algorithms. You can get your iterators by using buffer.data as start and buffer.data + buffer.size as end. So to copy the memory into a std::string you'd do something like so:
std::string str(buffer.data, buffer.data + buffer.size);
Or perhaps to append onto a string:
str.reserve(str.size() + buffer.size);
std::copy(buffer.data, buffer.data + buffer.size, std::back_inserter(str));
Of course you can always chose a different end so long as it's not past buffer.data + buffer.size.
They are using a char array so that you can access each byte of the data buffer since size of char is usually 1 byte.
Reading the contents of the data buffer depends on the application. If you know how the internal data is encoded, you can write an unpacking function which selects chunks of the char array and convert/typecast it to the target variables.
eg: Lets say the data buffer is actually a list of integers of size 4 bytes.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char const* argv[])
{
//how the data buffer was probably filled
int *a = (int *)malloc(10*sizeof(int));
int i;
for(i=0;i<10;i++) {
a[i] = i;
}
char *data = (char *)a;
//how we could read from the data buffer
int *b = (int *)malloc(10*sizeof(int));
char *p = data;
for(i=0;i<10;i++) {
b[i]=(int )*p;
printf("got value %d\n",b[i]);
p += sizeof(int);
}
free(a);
free(b);
return 0;
}
Note: That being said, since this is C++, it would be much safer if we could avoid using char pointers and work with strings or vectors. Other answers have explored other options of how to handle such buffers properly in C++.
I have following in my code:
static unsigned char* table;
...
table = something here;
Now I have to assign this table to variable of type std::vector<unsigned char> and I am unable to do so. I am doing:
unsigned char* buffer = (unsigned char*) table;
std::vector<unsigned char>::size_type size = strlen((const char*)buffer);
std::vector<unsigned char>static rawTable(buffer, buffer + size);
for(ByteBuffer::iterator it=rawTable.begin();it!=rawTable.end();++it)
std::cout << "Raw Table: "<<*it<< std::endl;
I am able to compile the code, but no value is there inside rawTable. Please help!
I have verified that variable table has value. I appreciate any help on this. Thanks.
strlen gives you the length of a string, not the size of an arbitrary memory region. If your table has a '\0' anywhere inside, strlen will find it and stop counting.
Also, by making rawTable a static variable, it will not update its value if buffer or size ever change. static variables are constructed only once.
Also, if this is supposed to be a table of numeric data, you should cast to a numeric non-character type. Otherwise cout may interpret it as ASCII codes.
You have a pointer of type unsigned char* pointing to an array.
Then you want to push every element of the array into a std::vector<unsigned char>, right?
If so, the key is to know the size of the array. You need to know the size beforehand. There's no way to determine the size of the array in the general case with some keyword or function if all that is visible to you is a pointer of type unsigned char*. You need to pass that information along with the pointer somehow.
In the case when the pointer of type unsigned char* points to an array of characters which is null-terminated (e.g. {'f', 'o', 'o', '\0'}), then you can use the C-string function strlen to count the number of characters in the array using only the pointer. However if the array is not null-terminated this will result in undefined behaviour.
When you have the size it's a simple matter to populate the std::vector with the arrays elements:
std::vector<unsigned char> v(arr, arr + size); // arr = pointer to array.
This is why you should use the containers in the standard library instead of raw arrays, as these containers internally keep track of the size and you can always access it with the size() function.
For constant size arrays use std::array. Example:
std::array<unsigned char, 3> arr{'f', 'o', 'o'}; // arr.size() == 3
// Print its contents.
for (auto c : arr) {
std::cout << c << std::endl;
}