J. Doe
J. Doe

Reputation: 83

Cast const std::vector<char> to unsigned char*?

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

Answers (3)

SajithP
SajithP

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

JustRufus
JustRufus

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

Telokis
Telokis

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 chars or unsigned chars 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

Related Questions