2012-11-24 4 views
1

cURL을 사용하여 C++로 웹 사이트에서 데이터를 가져 오기 위해 클래스를 작성하려고합니다. 다음은 그 클래스의 샘플입니다 (curl * curl_ 데이터 멤버가 있습니다. rawData_는 문자열입니다). 이 발췌 부분은 구현 파일에서 가져온 것입니다. 모든 함수는 헤더에 선언되어 있습니다.libcurl/cURL C++ segfault

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 함수에 segfault가 있습니다. 즉, buf는 크기가 0 인 것처럼 보입니다 (c = 0 일 때 buf [c] 호출이 중단됩니다). 어떤 도움을 주신다면

+0

'buf == this' 여부를 테스트 했습니까? –

+0

내가 걱정해야 할 것이 있나요? 내가 아는 한 'buf'는 웹 호출에 의해 전달 된 것입니다. 기본적으로 웹 사이트의 데이터 여야합니다. – GuestUser11111

+0

C++ 클래스 메서드에서 'this'는 정적 C 스타일 함수의 암시 적 첫 번째 인수로 생각할 수 있습니다. curl이 제공된 콜백을 C 스타일 함수 (마치) 인 것처럼 호출하면 적어도 호출 규칙은 호출 될 때 클래스 메소드에서 C++이 기대하기 때문에 호출 규칙이 아닙니다. –

답변

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를 선언 정적으로 (또는 비 멤버 친구로)와 (CURLOPT_WRITEDATAcurl_easy_setopt 사용) this에 유저 데이터를 설정하는 것입니다. 그런 다음 userdata 매개 변수를 MyClass으로 캐스팅하고 함수 내에서 사용할 수 있습니다.

+0

감사! 이것은 효과가 있었다. – GuestUser11111

+0

'curl_easy_setopt'는 가변 함수이므로 올바른 유형의 함수 매개 변수를 검사 할 수 없습니다. 그렇지 않으면 컴파일러가'size_t (X :: *) (char *, size_t, size_t, void *)'를'size_t (*) (char *, size_t, size_t, void *)'에 추가합니다. –

0

libcurl 맨 페이지 curl_easy_setopt에서 CURLOPT_WRITEFUNCTION이 설명되어있는 경우 빈 응답을 나타내는 경우와 같이 경우에 따라 "크기가 0 인"콜백이 호출 될 수 있습니다. 이 경우 적어도 size*nmemb의 제품은 0이어야하며 루프는 빈 버퍼로 입력되지 않으므로 안전하게 보관해야합니다.

그러나 CURLOPT_WRITEFUNCTION의 매개 변수에 대해서도 함수의 C++ 멤버 함수가 아니라 주어진 인수를 사용하여 설명합니다. 콜백 멤버 함수 본문 내의 암시적인 포인터가 buf으로 해석 될 수 있습니다. this (내부 클래스 상태)이 충돌과 동일한 행에서 처음으로 역 참조됩니다 (rawData_.push_back(buf[c])).

정말 빠르게 클래스 멤버 함수 콜백을 정적 함수 콜백 (즉 더 이상 MyClass의 멤버)으로 변환 해보세요. 그게 효과가있다. 그런 다음이 함수를 friend에서 MyClass으로 사용할 수도 있고 curl_easy_setopt으로 콜백을 설정할 때 CURLOPT_WRITEDATA 옵션에 적절한 this 포인터를 전달하면 클래스 멤버 함수에 대한 호출을 프록시하여 정적 비 멤버 함수를 허용 할 수 있습니다 적절한 C++ 클래스 메소드를 호출하여 클래스 객체에 대한 적절한 포인터를 호출한다.