I understand that using vector is a good way to store binary data when using C++ and the STL. However for my unit tests I'd like to initalise the vector using a const char* C string variable.
I'm attempting to use a variant of the code found here - Converting (void*) to std::vector<unsigned char> - to do this:
const char* testdata = "the quick brown fox jumps over the lazy dog.";
unsigned char* buffer = (unsigned char*)testdata;
typedef vector<unsigned char> bufferType;
bufferType::size_type size = strlen((const char*)buffer);
bufferType vec(buffer, size);
However the VC++ compiler is not happy with the line initialising the vector, stating:
error C2664: 'std::vector<_Ty>::vector(unsigned int,const _Ty &)' : cannot convert parameter 1 from 'char *' to 'unsigned int'
I appreciate the extreme n00bity of this question and am fully prepared for much criticism on the code above :)
Thanks in advance,
Chris
It should be
bufferType vec(buffer, buffer + size);
not
bufferType vec(buffer, size);
std::transform is useful for just this sort of problem. You can use it to "transform" one piece of data at a time. See documentation here:
http://www.cplusplus.com/reference/algorithm/transform/
The following code works in VS2010. (I created a std::string from your const char* array, but you could probably avoid that if you really wanted to.)
#include <algorithm>
#include <vector>
int main(int, char*[])
{
// Initial test data
const char* testdata = "the quick brown fox jumps over the lazy dog.";
// Transform from 'const char*' to 'vector<unsigned char>'
std::string input(testdata);
std::vector<unsigned char> output(input.length());
std::transform(input.begin(), input.end(), output.begin(),
[](char c)
{
return static_cast<unsigned char>(c);
});
// Use the transformed data in 'output'...
return 0;
}
Here is what worked for me:
// Fetch data into vector
std::vector<char> buffer = <myMethod>.getdata();
// Get a char pointer to the data in the vector
char* buf = buffer.data();
// cast from char pointer to unsigned char pointer
unsigned char* membuf = reinterpret_cast<unsigned char*>(buf);
// now convert to vector<unsigned char> buffer
std::vector<unsigned char> vec(membuf, membuf + buffer.size());
// display vector<unsigned char>
CUtils::<myMethodToShowDataBlock>(vec);
What you intended to do seems to be something like:
buffertype vec(testdata, next(testdata, strlen(testdata)));
There is no need for the intermediate buffer variable. The conversion from char to unsigned char will happen implicitly.
Note that this does not grab the terminating '\0' character from testdata. So if you wanted to be able to do something like: cout << vec.data() you wouldn't be able to. If you want that you could do: buffertype vec(testdata, next(testdata, strlen(testdata) + 1)) or you may just want to consider doing:
basic_string<unsigned char> vec(testdata, next(testdata, strlen(testdata)));
Which will preserve a hidden '\0'. Because this is not a string you won't be able to do, cout << vec but cout << vec.data() will work. I've created a Live Example of each of these.
Related
I've been working with OpenSSL library in C for a long time, but now I need to migrate to C++. OpenSSL's docs describe MD5 function like this.
unsigned char *MD5(const unsigned char *d, unsigned long n,
unsigned char *md);
I want to pass variable of type string to that function, but it accepts only char *.
Is it possible to pass string to parameter of type char * directly in C++? (I don't want to use extra manipulation with variable of type string)
You could use the c_str member function that std::string sports. Example
std::string data;
// load data somehow
unsigned char md[16] = { };
unsigned char *ret = MD5(reinterpret_cast<const unsigned char*>(data.c_str()),
data.size(),
md);
If you want to do away with the ugly cast operator, define a string class that holds unsigned chars instead of chars and use that.
typedef std::basic_string<unsigned char> ustring;
ustring data;
unsigned char *ret = MD5(data.c_str(), data.size(), md);
just a little note, which may save you a headache later on. MD5 takes an unsigned char pointer as a parameter. This is a clue that it's actually not a string, but a pointer to bytes.
In your program if you start storing byte vectors in a std::string, you're eventually going to initialise a string with a byte vector containing a zero, which opens the possibility of a bug that's difficult to detect down the line.
It is safer to store all your byte vectors in a std::vector<unsigned char> (or std::vector<uint8_t> because this forces safe initialisation.
std::vector<unsigned char> plaintext;
// initialise plaintext here
std::vector<unsigned char> my_hash(16);
MD5(plaintext.data(), plaintext.size(), &my_hash[0]);
I'm trying to write the contents of an untyped object that holds the bytes of an image into a vector filled with unsigned char. Sadly, i cannot get it to work. Maybe someone could point me in the right direction?
Here is what I have at the moment:
vector<unsigned char> SQLiteDB::BlobData(int clmNum){
//i get the data of the image
const void* data = sqlite3_column_blob(pSQLiteConn->pRes, clmNum);
vector<unsigned char> bytes;
//return the size of the image in bytes
int size = getBytes(clNum);
unsigned char b[size];
memcpy(b, data, size);
for(int j=0;j<size,j++){
bytes.push_back(b[j])M
}
return bytes;
}
If i try to trace the contents of the bytes vector it's all empty.
So the question is, how can i get the data into the vector?
You should use the vector's constructor that takes a couple of iterators:
const unsigned char* data = static_cast<const unsigned char*>(sqlite3_column_blob(pSQLiteConn->pRes, clmNum));
vector<unsigned char> bytes(data, data + getBytes(clNum));
Directly write into the vector, no need for additional useless copies:
bytes.resize(size);
memcpy(bytes.data(), data, size);
Instead of a copy, this has a zero-initialisation, so using the constructor like Maxim demonstrates or vector::insert is better.
const unsigned char* data = static_cast<const unsigned char*>(sqlite3_column_blob(pSQLiteConn->pRes, clmNum));
bytes.insert(data, data + getBytes(clNum));
I tried to convert QByteArray to std::vector<unsigned char> using this code:
unsigned char* buffer = (unsigned char*)byteArrayBuffer.constData();
std::vector<unsigned char>::size_type size = strlen((const char*)buffer);
std::vector<unsigned char> bufferToCompress(buffer, buffer + size);
but, assuming that byteArrayBuffer is a QByteArray filled with data, I think it doesn't work well on line unsigned char* buffer = (unsigned char*)byteArrayBuffer.constData(); because byteArrayBuffer.size() returns a different value than bufferToCompress.size().
How can I get it working?
I'm not familiar with Qt, but surely you just want
std::vector<unsigned char> bufferToCompress(
byteArrayBuffer.begin(), byteArrayBuffer.end());
Note: strlen is not particularly useful in C++; it tells you the length of a C-style null-terminated string (by searching memory until it either finds either finds a zero-valued byte, or falls off the end of accessible memory and crashes), but can't tell you the size of an array, which is what you'd need here. Also, using evil C-style casts to force invalid code to compile is never a good idea.
As I see here http://qt-project.org/doc/qt-4.8/qbytearray.html QByteArray does not have begin/end methods. But have data/length. Result code may be looks like this:
const unsigned char* begin = reinterpret_cast<unsigned char*>(byteArrayBuffer.data());
const unsigned char* end = begin + byteArrayBuffer.length();
std::vector<unsigned char> bufferToCompress( begin, end );
I have an unsigned char* c that contains the element 0x1c. How can I add it into an std::vector<unsigned char>vect? I am working in c++.
std::vector<unsigned char>vect; //the vect dimention is dynamic
std::string at="0x1c";
c=(unsigned char*)(at.c_str());
vect[1]=c //error? why?
//The vect dimension is dynamic ONLY if you call push_back
std::vector <std::string> vect;
std::string at="0x1c";
vect.push_back(at);
If you are using C++, use std::string. The above code will copy your "0x1c" string into the vector.
If you try to do
vect[0] = c;
Without first expanding the vector with
vect.resize(1);
You will get segmentation fault because operator[] doesn't expand the the vector dynamically. The initial size of a vector is 0 btw.
UPDATE: According to the OP's comment, here is what he would want: copying a unsigned char * to a std::vector (i.e.copying a C array to a C++ vector)
std::string at = "0x1c";
unsigned char * c = (unsigned char*)(at.c_str());
int string_size = at.size();
std::vector <unsigned char> vect;
// Option 1: Resize the vector before hand and then copy
vect.resize(string_size);
std::copy(c, c+string_size, vect.begin());
// Option 2: You can also do assign
vect.assign(c, c+string_size);
c is an unsigned char*. vect is a std::vector<unsigned char>, so it contains unsigned char values. The assignment will fail, as operator [] on std::vector<unsigned char> expects an unsigned char, not a unsigned char *.
You have a hex representation of a character in a string, and you want the character?
easiest:
unsigned char c;
istringstream str(at);
str >> hex >> c; // force the stream to read in as hex
vect.push_back(c);
(I think that should work, have not tested it)
I just reread your question again, this line:
I have an unsigned char* c that
contains the element 0x1c
Does this mean that actually your unsigned char* looks like this:
unsigned char c[] = {0x1c}; // i.e. contains 1 byte at position 0 with the value 0x1c?
or my assumption above...
to print the vector out to cout, use a simple for loop, or if you are feeling brave
std::cout << std::ios_base::hex;
std::copy(vect.begin(), vect.end(), std::ostream_iterator<unsigned char>(std::cout, " "));
std::cout << std::endl;
this will print the hex representations of each of the unsigned char values in the vector separated by a space.
sqlite3_column_text returns a const unsigned char*, how do I convert this to a std::string? I've tried std::string(), but I get an error.
Code:
temp_doc.uuid = std::string(sqlite3_column_text(this->stmts.read_documents, 0));
Error:
1>.\storage_manager.cpp(109) : error C2440: '<function-style-cast>' : cannot convert from 'const unsigned char *' to 'std::string'
1> No constructor could take the source type, or constructor overload resolution was ambiguous
You could try:
temp_doc.uuid = std::string(reinterpret_cast<const char*>(
sqlite3_column_text(this->stmts.read_documents, 0)
));
While std::string could have a constructor that takes const unsigned char*, apparently it does not.
Why not, then? You could have a look at this somewhat related question: Why do C++ streams use char instead of unsigned char?
On the off-chance you actually want a string of unsigned characters, you could create your own type:
typedef std::basic_string <unsigned char> ustring;
You should then be able to say things like:
ustring s = sqlite3_column_text(this->stmts.read_documents, 0);
The reason people typically use an (unsigned char *) type is to indicate that the data is binary and not plain ASCII text. I know libxml does this, and from the looks of it, sqlite is doing the same thing.
The data you're getting back from the sqlite call is probably UTF-8 encoded Unicode text. While a reinterpret_cast may appear to work, if someone ever stores text in the field that is not plain ASCII, your program probably won't be well-behaved.
The std::string class isn't designed with Unicode in mind, so if you ask for the length() of a string, you'll get the number of bytes, which, in UTF-8, is not necessarily the same thing as the number of characters.
Short answer: the simple cast may work, if you're certain the data is just ASCII. If it can be any UTF-8 data, then you need to handle encoding/decoding in a smarter way.
I'm not familiar with sqlite3_column_text, but one thing you may want to do is when you call the std:string constructor, you'll want to cast to (const char*). I believe that it should have a constructor for that type.
However, it is odd that this sqlite function is return an unsigned char*, is it returning a Pascal string (first char is the length of the string)? If so, then you'll have to create the std::string with the bytes and the length.
if temp_doc.uuid is a std::string try :
temp_doc.uuid = static_cast<const char*>(sqlite3_column_text(this->stmts.read_documents, 0));
try:
temp_doc.uuid = std::string(reinterpret_cast<const char*>(sqlite3_column_text(this->stmts.read_documents, 0)));
You can't construct a std::string from const unsigned char* -- you have to cast it to const char* first:
temp_doc.uuid = std::string( reinterpret_cast< const char* >(
sqlite3_column_text(this->stmts.read_documents, 0) ) );
I'm no expert but this example here seems much simpler:
string name = (const char*) (sqlite3_column_text(res, 0));
An old but important question, if you have to preserve the full information in the unsigned char sequence. In my opinion that is with reinterpret_cast not the case. I found an interesting solution under converting string to vector
which I modified to
basic_string<unsigned char> temp = sqlite3_column_text(stmt, 0);
string firstItem( temp.begin(), temp.end() );
Since I am programming for gtkmm, you can realize the conversion into a Glib::ustring with
basic_string<unsigned char> temp = sqlite3_column_text(stmt, 0);
Glib::ustring firstItem = string( temp.begin(), temp.end() );