2013-11-30 1 views
0

Я хочу написать оболочку для функции обратного вызова для информации о ходе выполнения libcurl в C. Эта оболочка должна рассчитать некоторые данные, которые должны быть инкапсулированы в библиотеку.Вызов функции из указателя функции в структуре

Вот описание основной идеи: (я надеюсь, что это проясняет вещи)

Пользователь должен реализовать функцию обратного вызова xFunc и инициализировать структуру данных для хранения данных для функции обратного вызова (так называемого XDATA). Затем он должен вызвать функцию-оболочку aFunc. В качестве аргумента он предоставляет некоторые связанные с соединением данные и указатель на xFunc и xData. В aFunc вычисляются некоторые вещи, которые требуются для вызова второй функции bFunc. Указатель xFunc и xData также передаются этой функции. В этой функции инициализируется вторая структура данных YData. Эта структура содержит указатель на предоставленные пользователем xFunc и xData и некоторые другие данные, которые необходимы для вычислений. Теперь связанные с libcurl вещи инициализируются. В качестве обратного вызова для процесса загрузки в библиотеке реализована вторая функция обратного вызова yFunc. В этой функции пользователь, которому предоставляется xFunc, должен вызываться с xData и другими рассчитанными значениями.

Теперь вот код моего текущей реализации (. Я разделся весь код вычисления и переименовал функции и структуры, математике описание выше, так это выглядит немного странно, я надеюсь, что это не слишком абстрактно сейчас):

main.c

int xFunc(void *xData, long int param1, long int param2) { 
    //do something with the data 
    return 0; 
} 

int main(void){ 

    xpData *xData; 
    xData->value = 0; 

    aFunc(xFunc, p); 

    return 0; 
} 

curlutils.h

typedef struct { 
    int value; 
} xpData; 

int xFunc(void *xData, long int param1, long int param2); 
int aFunc(int (*xFunc)(void*, long int, long int), void xData); 
int bFunc(int (*xFunc)(void*, long int, long int), void xData); 

curlutils.c

typedef struct { 
    int (*xFunc)(void*, long int, long int); 
    void *data;  
} ypData; 


int yFunc(void *p, double dltotal, double dlnow, double ultotal, double ulnow){ 
    ypData *pd; 
    pd = (ypData*) p;  
    return pd->xFunc(pd->data); 
} 

int bFunc(int (*xFunc)(void*, long int, long int), void xData){ 
    CURL *curl; 
    curl_global_init(CURL_GLOBAL_ALL); 
    curl = curl_easy_init(); 
    if (curl){ //stripped many curl initialization stuff 
     ypData *yData; 
     yData->data = xData; 
     yData->xFunc = xFunc; 
     curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, yFunc); 
     curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &yData); 
     curl_easy_perform(curl); 
    } 
    return 0; 
} 

int aFunc(int (*xFunc)(void*, long int, long int), void *xData){ 
    //calculate something useful 
    bFunc(xFunc, xData); 
    return 0; 
} 

Проблема заключается в yFunc, где я хочу назвать xFunc. Программа вылетает с ошибкой:

Illegal instruction 

Почему этот код не работает?

+1

Я не могу себе представить, что это ваш настоящий код. 'void xData' не является допустимым параметром для функции,' bfunc' и 'bFunc' - не тот же идентификатор, а ваш параметр' xFunc' для 'bFunc' даже не используется. Голосование закрывается. –

+0

Извините, я отредактировал код в соответствии с вашими критиками. Мой настоящий код немного беспорядочен и нелегко понять, поэтому он абстрагируется здесь. – Noir

+0

Как всегда УБЕДИТЕСЬ, ЧТОБЫ ВКЛЮЧИТЬ ВСЕ ПРЕДОХРАНИЛИЩИЕ ПРЕДУПРЕЖДЕНИЯ (используйте '-Wall') и найдите время, чтобы понять, что компилятор вам говорит. –

ответ

1

Проблема в том, что когда вы передаете указатели как указатели void, вы не получаете никаких предупреждений, если вы передаете неправильный указатель. Затем, когда вы бросаете указатель, вы применяете его к неправильному типу и, вероятно, переходите к недопустимому адресу.

У вас есть:

ypData *yData; 
    yData->data = xData; 
    yData->xFunc = xFunc; 
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, yFunc); 
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &yData); 

Объявляет указатель нахо вар yData но не инициализирует его. Затем вы быстро разыщите указатель, который, скорее всего, сработает (и должен дать предупреждение о времени компиляции). Если это не так, вы затем передаете &yData (то есть ypData **) в yFunc (косвенно через curl_easy_setopt), который ожидает в качестве аргумента ypData *.

Вы можете быть в состоянии исправить это с помощью:

ypData yData; 
    yData.data = xData; 
    yData.xFunc = xFunc; 
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, yFunc); 
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &yData); 
    curl_easy_perform(curl); 

это имеет потенциальную опасность, если один из curl функций копить указатель на yData и позже curl вызов пытается вызвать yFunc после этой функции (и указатель свисает).Если это может случиться, что вам нужно что-то вроде:

ypData *yData = malloc(sizeof *yData); 
    yData->data = xData; 
    yData->xFunc = xFunc; 
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, yFunc); 
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, yData); 

у которой есть проблемы, которые вы не знаете, когда, чтобы освободить выделенную yData, поэтому подвержены утечкам памяти.

+0

Спасибо, ты мне очень помог. :) Странно, что компилятор не показывает мне предупреждения даже с -Wall ... – Noir