将const std::vector<char>转换为unsigned char*,应该怎么做?

3

为C库编写C++包装器。库中有一个函数接受缓冲区作为unsigned char *。由于使用C++,我将真正的缓冲区存储在std::vector<char>中,此外,在包装器类中,我还添加了const,因为问题中的缓冲区是输入缓冲区,并且不会被修改。但我的代码无法编译,演示:

#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
}

id有什么问题吗?如果我从const std::vector<char> s(10);中去掉consts,它就可以工作了,但我更喜欢这种方式。


这将是一个 const_cast 而不是 reinterpret_cast。但为什么 x 不接受 const unsigned char* - overseas
因为我们也不会写 unsigned char *s = "hello world",我们会写 char * ;) - J. Doe
@J.Doe 尽管被踩了,我相信我已经回答了你的问题。我还添加了一些关于概念背后逻辑的细节。 - Telokis
是的,我很感激。一旦出现接受解决方案的按钮,我会立即接受它。 - J. Doe
这里有两个问题:1)x()不是正确的const,它应该采用const unsigned char*。2)reinterpret_cast不能去除const,它可以将const char*转换为const unsigned char*,但不能转换为unsigned char*。如果您可以修改x(),则无需删除sconst - Justin Time - Reinstate Monica
很不幸,我正在为 C 库的头文件制作一个包装器,而 x() 已经按照原样定义在其中(无法更改)。 - J. Doe
3个回答

7

您需要使用const_cast来去除常量性,然后使用reinterpret_castchar *转换为unsigned char *

试试这个:x(reinterpret_cast<unsigned char*>(const_cast<char *>(s.data())));

注意:但也要记住,const_cast只有在您转换的变量最初是非常量时才安全。请参见答案。


我不记得 static_cast 允许将 char* 转换为 unsigned char* - chris
@chris 哎呀,你说得对。我更新了我的答案以使用reinterpret_cast。 - JustRufus

1
你的错误是因为你将std::vector声明为const
如果你去掉const,它就能正常工作。(如这里所示)
无论如何,你应该问问自己是否真的需要在数组中存储charunsigned char
如果你想保留const,你必须使用const_cast,但你的代码会变得很长: x(const_cast<unsigned char*>(reinterpret_cast<const unsigned char *>(s.data()))); 如果你可以访问库,最好将缓冲区标记为const(如果它没有被修改)。但是,由于它不是const,你不能确定函数是否会修改它,因此,你不应该将std::vector保留为const

OP特别提到了这一点,并表示他们不想放弃const - Rakete1111
是的,但我不能立即打字,很抱歉。 - Telokis
耶稣。Bjourstroup先生做得非常好。您在发明C++时为什么没有考虑到这个混乱?我想我会坚持使用C风格(unsigned char *)转换。 - J. Doe
@J.Doe,不安全和不寻常的转换之所以混乱,是有原因的。任何看到这行代码的人都会立刻知道有一些可疑的东西正在发生,这很恰当,因为你正在去掉 const,同时切换了符号。 - chris
“Shady stuff”说得好。 - J. Doe
显示剩余2条评论

-1

这是我在跨平台实现中解决相同问题的方法。上述方法在Windows和Linux(Redhat)上运行良好,但在Solaris 10和IBM AIX 7上不起作用。

Solaris 10使用上述建议的方法会出现以下错误。 'nofieldident: data is not a member of const std::vector<unsigned char>'

以下是一种处理向量数据的'const'性质的方法,可在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

为什么要踩票呢?:(这是经过测试的代码,可解决Windows 2008、2008R2、2010、2010R2、2016、Linux RHEL5和7、Soloris 8和10、IBM AIX 7以及32位和64位平台上的const问题。 - SajithP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接