【问题标题】:Pass data as a void* in C++在 C++ 中将数据作为 void* 传递
【发布时间】:2014-11-09 17:56:53
【问题描述】:

我在我的 c++ 程序中使用 curl。 Curl 可以存储传递给它的“用户数据”,这样当我收到 curl HTTP 回调时,我可以再次检索此用户数据。

Curl 会将此数据存储为 void*。我希望能够将数据传递给这样的函数:

void SomeFunction( const std::string& url, const std::string& username, const std::string& password, void* userData)
{
    //Pass userData to curl..blah blah
}

我的问题是将数据作为 void* 传递的正确和正确的 C++ 方法是什么? 我应该有这样的界面吗:

    class ICurlUserData
    {
    public:
        virtual void SetCurlData( void* pUserData ) = 0;
        virtual void* GetCurlData( void ) = 0;
    };

然后让一个类像这样实现这个接口:

    class CurlUserData
    {
    public:
        CurlUserData() : m_userData(nullptr){};
        virtual ~CurlUserData(){};

        virtual void SetCurlData( void* pUserData ){ m_userData = pUserData;}
        virtual void* GetCurlData( void ){ return m_userData; }
    private:
        void* m_userData;
    };

然后像这样传递:

void SomeFunction( const std::string& url, const std::string& username, const std::string& password, ICurlUserData* userData)
{
    CurlUserData data = static_cast<CurlUserData*>(userData);
    void* myData = data->GetCurlData();
    int myNumber = static_cast<int>(myData); 
    //blah blah
}

感谢您的帮助

【问题讨论】:

  • 嗯,你的问题有一个很好的答案!我想另一种选择可能是制作一个template &lt;type T&gt; void SomeFunction( const string&amp; url, const string&amp; username, const string&amp; password, T&amp; userData)
  • 为什么不像你最初展示的那样直接将 userData 作为void* 传递?为什么要费尽心思去强制它呢?让调用者将它想要的任何数据传递给SomeFunction(),它在 C++ 中工作得很好。仅仅因为 C++ 支持/强调结构化数据并不意味着您必须将它用于所有事情。例如,如果调用者想要传递一个简单的int* 指针怎么办?像你展示的那样包装它是多余的。

标签: c++ curl interface


【解决方案1】:

void* 数据传递给curl(或任何其他)回调您的C 函数的正确方法如下:

StronglyTyped myobj;

extern "C" void myfunc (void* arg)
{
   StronglyTyped* p_myobj = static_cast<StronglyTyped*>(arg);
   // do something
}


//.. somewhere in your code ...
curl_something(curlarg1, curlarg2, myfunc, static_cast<void*>(&myobj));

这三个 void* 应该是您唯一使用的。

更新,跟进 cmets 中的讨论

不可能摆脱这些void* 的出现。 C 函数不能使用模板、派生类或各种其他高级技术。如果它想回调一个用户函数并将一些用户数据传回给它,它必须使用 `void* 指针。因此,需要回调的 C 函数通常接受两个如下所示的参数:

void c_function_with_a_callback ( ..., ..., 
                                void (*user_function)(void*), 
                                void* user_data);

传递给函数的两个实际参数必须具有完全签名中指定的类型,因此必须编写一个具有此签名的函数:

 void somefunction (void*);

而且必须有一个void* 指针传递给它。后者通常通过强制转换从常规对象指针中获得。 somefunction 通常会在第一行恢复强类型对象指针。

没有必要有任何其他的void* 指针——不是任何由相关“curl”函数指定的。

确实,如果有问题的函数是用 C++ 编写的,它很容易成为一个函数模板:

template <typename T>
void void cxx_function_with_a_callback (..., ...,
                                       void (*user_function)(T*),
                                       T* user_data);

此版本中没有void*,但它与C 版本基本相同。带有c_function_with_a_callback 的系统和带有cxx_function_with_a_callback 的系统之间的唯一区别是:

  1. user_function 的类型
  2. user_data 的类型
  3. void* 之间存在或不存在两个转换

如果带有cxx_function_with_a_callback 的系统在任何地方都没有void*,那么带有c_function_with_a_callback 的类似系统应该有void* 指针正好在上面列举的位置而不是其他位置。如果带有cxx_function_with_a_callback 的系统出于某种原因需要void*,那么带有c_function_with_a_callback 的系统在类似的地方也将需要void*,但是这些void* 的东西与c_function_with_a_callback 的存储方式无关用户数据。

【讨论】:

  • 谢谢。但是我将数据传递给的函数是 C++ 函数,而不是直接的 C。
  • myfunc 是一个 C++ 函数。 C 函数将无法执行 static_cast
  • 是的,但您的 C++ 函数仍在使用 void* 作为其参数。如果可能的话,我想摆脱它。
  • 你不能。 curl 函数需要void(*)(void*),即具有void* 参数的函数。这正是你应该传递给它的。您的尝试出现了大约 6 次 void*,但似乎都没有任何用途。您应该在 C 或其他遗留接口需要void* 的地方使用void*。您的代码不会尝试调用旧接口。与其解决如何在 C++ 中传递 void* 的全局问题(这没有任何意义),不如写下您计划调用的curl 函数的签名,然后问“我如何给这个人打电话并取回我的数据?”
猜你喜欢
  • 1970-01-01
  • 2012-11-19
  • 2021-11-19
  • 1970-01-01
  • 2012-10-06
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 2019-01-28
相关资源
最近更新 更多