我正在尝试编写一个类来使用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]的调用时中断)。任何帮助表示赞赏
答案 0 :(得分:4)
curl_easy_setopt
CURLOPT_WRITEFUNCTION
的参数应为size_t function( char *ptr, size_t size, size_t nmemb, void *userdata)
类型。这是一个“干净”的C函数,而不是一种方法。
但据我所知,您传递的是非静态方法的地址。所以它没有正确的签名(我猜它是非静态的,因为你在里面使用rawData_
。)
现在,curl_easy_setopt
并不在乎 - 它需要你付出的任何东西。但是当它调用函数时会发生不好的事情。
我的建议是将writeCallback
声明为静态(或甚至是非会员朋友)并将用户数据设置为this
(使用curl_easy_setopt
CURLOPT_WRITEDATA
) 。然后,您可以将userdata参数强制转换为MyClass
并在函数内使用它。
答案 1 :(得分:0)
在解释curl_easy_setopt
的libcurl联机帮助页CURLOPT_WRITEFUNCTION
中,它指出在某些情况下可以使用“零大小”调用回调,例如指示空响应。在这种情况下,至少size*nmemb
的乘积应为零,因此您的循环永远不会输入空缓冲区,因此您应该在那里安全。
但是,它还将CURLOPT_WRITEFUNCTION
的参数描述为使用给定参数的函数,而不是C ++成员函数。很可能是回调成员函数体中的隐式this
指针被解释为buf
。恰好,this
(内部类状态)第一次在与崩溃相同的行中被取消引用:rawData_.push_back(buf[c])
。
快速,尝试将您的类成员函数回调转换为静态函数回调(即,不再是MyClass
的成员)。这应该工作。然后,您可以将此函数用作friend
到MyClass
,或者如果将适当的this
指针传递给CURLOPT_WRITEDATA
,则可以代理对类成员函数的调用。使用curl_easy_setopt
设置回调时的选项,允许静态非成员函数使用指向类对象的相应指针调用相应的C ++类方法。