libcurl/cURL C++段错误

3

我正在尝试编写一个类来使用C++和cURL从网站获取一些数据。以下是该类的示例代码(其中有一个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]时会中断)。任何帮助都将不胜感激。


你测试过 buf == this 吗? - Matthew Hall
这是我应该担心的事情吗?据我所知,buf是由Web调用传递的东西;它应该基本上是网站的数据。 - GuestUser11111
我想表达的是,对于C++类方法而言,this可以被视为静态C风格函数的隐式第一个参数。如果curl调用您提供的回调函数就像调用C风格函数一样(实际上就是这样),至少在调用类方法时,调用约定与C++所期望的不同,会导致未定义的情况发生。 - Matthew Hall
2个回答

5
curl_easy_setopt的参数CURLOPT_WRITEFUNCTION应该是一个类型为size_t function(char *ptr, size_t size, size_t nmemb, void *userdata)的“干净”的C函数,而不是一个方法。但据我所见,您正在传递非静态方法的地址。因此,它将没有正确的签名(我猜测它是非静态的,因为您在其中使用了rawData_)。现在,curl_easy_setopt并不真正关心它接收到什么。但当它调用该函数时,会发生糟糕的事情。我的建议是将writeCallback声明为静态(甚至作为非成员友元),并将userdata设置为this(使用curl_easy_setoptCURLOPT_WRITEDATA)。然后,您可以将userdata参数转换为MyClass并在函数内部使用它。

很遗憾,curl_easy_setopt是一个可变参数函数,因此无法检查函数参数的正确类型。否则,编译器肯定会报错,指出无法将size_t (X::*)(char*, size_t, size_t, void*)转换为size_t (*)(char*, size_t, size_t, void*) - Adam Rosenfield

0
在libcurl manpage中,解释了curl_easy_setoptCURLOPT_WRITEFUNCTION,它指出回调有时可能会被调用为“零大小”,例如表示空响应。在这种情况下,至少size*nmemb的乘积应该为零,因此您的循环永远不会进入空缓冲区,所以您是安全的。
然而,它还描述了CURLOPT_WRITEFUNCTION的参数为使用给定参数的函数,而不是C++成员函数。你的回调成员函数体内隐式的this指针可能被解释为buf。恰好在崩溃的同一行上第一次解引用this(内部类状态):rawData_.push_back(buf[c])

快速尝试将您的类成员函数回调转换为静态函数回调(即不再是MyClass的成员)。那应该可以工作。然后,您可以将此函数用作MyClassfriend,或者如果在使用curl_easy_setopt设置回调时传递了适当的this指针到CURLOPT_WRITEDATA选项,则可以代理对类成员函数的调用,从而允许您的静态非成员函数使用适当的类对象指针调用相应的C++类方法。


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