从struct中的函数指针调用函数

时间:2013-11-30 17:57:20

标签: c gcc function-pointers libcurl

我想为C中的libcurl的进度信息编写回调函数的包装器。 这个包装器应该计算一些应该封装在库中的数据。

以下是对基本概念的描述:(我希望这能澄清事情)

用户应该实现一个回调函数xFunc并初始化一个数据结构来存储回调函数的数据(称为xData)。然后他应该调用包装函数aFunc。作为参数,他提供了一些与连接相关的数据以及指向xFunc和xData的指针。在aFunc中,计算了调用第二个函数bFunc所需的一些东西。 xFunc和xData指针也传递给此函数。在该函数中,初始化第二数据结构YData。此结构包含指向用户提供的xFunc和xData以及计算所需的一些其他数据的指针。现在libcurl相关的东西被初始化了。作为上传进度的回调,在库中实现了第二个回调函数yFunc。在此函数中,应使用xData和其他计算值调用用户提供的xFunc。

现在这里是我当前实现的代码(我删除了所有的计算代码并重命名了函数和结构,以便对上面的描述进行数学运算,所以它看起来有点奇怪。我希望它现在不太抽象):

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 个答案:

答案 0 :(得分:1)

问题在于,当您将指针作为void指针传递时,如果传递错误类型的指针,则不会收到任何警告。然后当你转换指针时,你将其转换为错误的类型,并可能跳转到无效的地址。

你有:

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

这声明了一个locat指针var yData但不初始化它。然后,您可以立即取消引用指针,这可能会崩溃(并且应该给出编译时警告)。如果没有,则您将&yDataypData **)传递给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

有一个问题,你不知道何时释放分配的{{1}},因此会受到内存泄漏的影响。