Reputation: 83
Writing a C++ wrapper for a C library. In the library there is a function which accepts a buffer as unsigned char *
. Since working with C++ I store my real buffer in std::vector<char>
, moreover, in the wrapper class I also added const
, because the buffer in question is an input buffer and it wont get modified. But my code does not compile, demo:
#include <stdio.h>
#include <vector>
void x(unsigned char *s)
{
printf("%s\n", s);
}
int main()
{
const std::vector<char> s(10);
x(reinterpret_cast<unsigned char *>(s.data())); // FAILS
}
What is wrong with id? If I remove the consts
from const std::vector<char> s(10);
it works, but I would prefer it that way.
Upvotes: 3
Views: 2694
Reputation: 587
This is how I fixed the same problem during my cross platform implementations. Above methods worked fine on Windows and Linux (Redhat) but not on Solaris 10 and IBM AIX 7.
Solaris 10 gives following error with above suggested methods.
'nofieldident: data is not a member of const std::vector<unsigned char>'
Here is a way to work with the 'const'
ness of vector data, which will work across Windows, Linux, Solaris
#include <iostream>
#include <vector>
using namespace std;
/// Data Interface, which is visible to the outside
class IDataInterface {
public:
// Get the underlying data as a const data pointer
virtual const unsigned char* Data(size_t& nSize) = 0;
};
/// Implemetation of the IDataInterface
class CData : public IDataInterface {
public:
// Constructor
CData(vector<unsigned char> data);
// Overriden function of the interface
const unsigned char* Data(size_t& nSize);
private:
/// Actual data member
vector<unsigned char> m_vData;
};
/// Constructor implementation
CData::CData(vector<unsigned char> vData) {
// resize to the input data size
m_vData.resize(vData.size());
// Copy the data
memcpy(&m_vData[0], &vData[0], vData.size());
}
/// Implementation of the data function
const unsigned char* CData::Data(size_t& nSize /**< Size of data returned */) {
/*
* Following four methods worked fine on Windows, RedHat, but Failed on Solaris 10 and IBM AIX
*/
// return &m_vData[0];
// return m_vData.data();
// return const_cast<unsigned char*>(reinterpret_cast<const unsigned char *>(m_vData.data()));
// return reinterpret_cast<unsigned char*>(const_cast<unsigned char *>(m_vData.data()));
/* This was tested on following and works fine.
* Windows (Tested on 2008 to 2016, 32/64 bit, R2 versions)
* RedHat 5&7 (32/64 bit)
* Solaris 10 (32/64 bit)
* IBM AIX 7.10
*
*/
return &m_vData.front(); --> This works on windows, redhat, solaris 10, aix
}
/// Main class
int main() {
// Vector of data
vector<unsigned char> vData;
// Add data onto the vector
vData.push_back('a');
vData.push_back('b');
vData.push_back('c');
// Create an instance from the vector of data given
CData oData(vData);
// Get the data from the instance
size_t nSize(0);
cout << "Data:" << oData.Data(nSize) << endl;
return 0;
}
Output:
Data:abc
Upvotes: -1
Reputation: 542
You have to do const_cast
to remove constness and then reinterpret_cast
to cast char *
into unsigned char *
Try this: x(reinterpret_cast<unsigned char*>(const_cast<char *>(s.data())));
Note: But also remember that const_cast
is safe only if you're casting a variable that was originally non-const. See this answer.
Upvotes: 7
Reputation: 3389
Your error is because you declare your std::vector
as const
.
If you drop the constness, it works properly. (As seen here)
Anyway, you should ask yourself if you really need to store char
s or unsigned char
s in your array.
If you want to keep the const
, you would have to use a const_cast
but your line would become pretty long :
x(const_cast<unsigned char*>(reinterpret_cast<const unsigned char *>(s.data())));
If you have access to the library, it would have been better to mark the buffer as const
if it isn't changed.
But, since it isn't const
, you can't be sure it won't be modifier by the function and, because of that, you shouldn't keep your std::vector
as a const
.
Upvotes: 1