3

我正在尝试编写一个类以使用 cURL 从 C++ 网站获取一些数据。这是该类的一个示例(有一个 Curl* curl_ 数据成员, rawData_ 是一个字符串)。这段摘自实现文件,所有函数都在头文件中声明。

MyClass::MyClass()
{
    curl_global_init(CURL_GLOBAL_ALL);
    curl_ = curl_easy_init();

    curl_easy_setopt(curl_, CURLOPT_URL,
               "http://www.google.com");
    curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, &MyClass::writeCallback);

}

MyClass::~MyClass()
{
    curl_easy_cleanup(curl_);
    curl_global_cleanup();
}

size_t MyClass::writeCallback(char* buf, size_t size, size_t nmemb, void* up)
{
    //buf is a pointer to the data that curl has for us
    //size*nmemb is the size of the buffer
    for (size_t c = 0; c<size*nmemb; ++c)
    {
        cerr << c << endl;
        rawData_.push_back(buf[c]);
    }
    return size*nmemb; //tell curl how many bytes we handled
}

void MyClass::makeCall()
{
    curl_easy_perform(curl_);
}

当我创建 MyClass 的实例并调用 makeCall 时,writeCallBack 函数中有一个段错误。也就是说,buf 的大小似乎为 0(当 c = 0 时,它在 buf[c] 的调用中中断)。任何帮助表示赞赏

4

2 回答 2

5

curl_easy_setoptwith的参数CURLOPT_WRITEFUNCTION应该是类型size_t function( char *ptr, size_t size, size_t nmemb, void *userdata)。那是一个“干净”的 C 函数,而不是一种方法。

但据我所知,您传递的是非静态方法的地址。所以它不会有正确的签名(我猜它是非静态的,因为你在rawData_里面使用)。

现在,curl_easy_setopt真的不在乎 - 它需要你给它的任何东西。但是当它调用这个函数时,坏事就会发生。

我的建议是声明writeCallback为静态(甚至作为非成员朋友)并将用户数据设置为this(使用curl_easy_setoptwith CURLOPT_WRITEDATA)。然后,您可以将 userdata 参数转换为MyClass并在函数内使用它。

于 2012-11-24T01:11:44.727 回答
0

在解释的 libcurl 手册页curl_easy_setoptCURLOPT_WRITEFUNCTION,它指出在某些情况下可能会以“零大小”调用回调,例如指示空响应。在这种情况下,至少 的乘积size*nmemb应该为零,因此您的循环永远不会使用空缓冲区进入,因此您应该在那里安全。

但是,它也将参数描述为CURLOPT_WRITEFUNCTION带有给定参数的函数,而不是 C++ 成员函数。很可能是this回调成员函数体内的隐式指针被解释为buf. 碰巧this(内部类状态)第一次在与您的崩溃相同的行上被取消引用:rawData_.push_back(buf[c]).

真的快,尝试将您的类成员函数回调转换为静态函数回调(即,不再是 的成员MyClass)。那应该行得通。然后,您可以将此函数用作friendto ,或者如果您在使用 设置回调时将适当的指针MyClass传递给选项,则可以代理对类成员函数的调用,从而允许您的静态非成员函数调用适当的 C++具有指向类对象的适当指针的类方法。thisCURLOPT_WRITEDATAcurl_easy_setopt

于 2012-11-24T01:11:57.080 回答