QObject派生类回调函数到c库

时间:2013-07-30 21:12:58

标签: c++ qt

我试图将libcurl包装为辅助QObject类。不幸的是,我得到了一个神秘的段错误,当完全相同的代码放在一个类之外时不会发生。

示例代码:

无类别工作代码

//main.cpp
size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* up)
{
    size_t data_size = size * nmemb;
    QByteArray *data = static_cast<QByteArray*>(up);
    data->append(ptr, data_size);
    return data_size;
}

int main(int argc, char *argv[]) {

    QCoreApplication a(argc, argv);  

    QByteArray buffer;  
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://cnn.com");
        /* example.com is redirected, so we tell libcurl to follow redirection */
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

        /* always cleanup */
        curl_easy_cleanup(curl);
    }
    qDebug() << buffer;
    return a.exec();
}

段落错误

的QObject包装器
//Http.h 
class Http : public QObject
{
    Q_OBJECT
public:
    Http();
    void download();
signals:
    void finished(const QByteArray &buffer);
private:
    size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* up);
};

//Http.cpp
Http::Http()
{

}

void Http::download()
{
    QByteArray buffer;

    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://cnn.com");
        /* example.com is redirected, so we tell libcurl to follow redirection */
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &Http::writeCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

        /* always cleanup */
        curl_easy_cleanup(curl);
    }

    qDebug() << buffer;
    emit finished(buffer);
}

size_t Http::writeCallback(char* ptr, size_t size, size_t nmemb, void* up)
{
    size_t data_size = size * nmemb;

    QByteArray *data = static_cast<QByteArray*>(up);
    data->append(ptr, data_size); //<--SEGFAULTS

    return data_size;
}

//main.cpp
int main(int argc, char *argv[]) {

    QCoreApplication a(argc, argv);  
    Http http;
    http.download();
    return a.exec();
}

Http::writeCallback(char* ptr, size_t size, size_t nmemb, void* up)

中存在段错误的行

valgrind输出

    ==11246== Invalid read of size 1
    ==11246==    at 0x4C2D7A2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==11246==    by 0x511EA14: QByteArray::append(char const*, int) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.0.1)
    ==11246==    by 0x401B77: Http::writeCallback(char*, unsigned long, unsigned long, void*) (http.cpp:45)
    ==11246==    by 0x4E48717: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
    ==11246==    by 0x4E64A1B: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
    ==11246==    by 0x4E5F8B1: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
    ==11246==    by 0x4E68739: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
    ==11246==    by 0x4E693D4: curl_multi_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
    ==11246==    by 0x4E60FDC: curl_easy_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)

==11246==    by 0x401A45: Http::download() (http.cpp:26)
==11246==    by 0x401838: main (main.cpp:57)
==11246==  Address 0x1 is not stack'd, malloc'd or (recently) free'd
==11246== 
==11246== 
==11246== Process terminating with default action of signal 11 (SIGSEGV)
==11246==  Access not within mapped region at address 0x1
==11246==    at 0x4C2D7A2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11246==    by 0x511EA14: QByteArray::append(char const*, int) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.0.1)
==11246==    by 0x401B77: Http::writeCallback(char*, unsigned long, unsigned long, void*) (http.cpp:45)
==11246==    by 0x4E48717: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246==    by 0x4E64A1B: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246==    by 0x4E5F8B1: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246==    by 0x4E68739: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246==    by 0x4E693D4: curl_multi_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246==    by 0x4E60FDC: curl_easy_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246==    by 0x401A45: Http::download() (http.cpp:26)

我完全失去了代码失败的原因。

PS。我知道这个示例代码是阻塞的,我知道有QNetworkAccessManager。我打算稍后将它移到QThread。我之所以使用libcurl,是因为我需要点击的网络服务与QNAM发送的默认标头不一致。

1 个答案:

答案 0 :(得分:2)

You can't pass C++ member methods as C callbacks。使回调成为类的静态方法,或者是一个顶级自由函数。