从结构体中的函数指针调用函数

标签 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

为什么这段代码不起作用?

最佳答案

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

你有:

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

这声明了一个定位指针 var yData 但没有初始化它。然后,您立即取消引用该指针,这可能会崩溃(并且应该给出编译时警告)。如果没有,则将 &yData (这是 ypData **)传递给 yFunc (间接通过 curl_easy_setopt code>),它需要 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,因此容易发生内存泄漏。

关于从结构体中的函数指针调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20303668/

相关文章:

c - 为什么这个小程序输出True? GCC有溢出保护吗?

c - 以两种不同方式指向动态库的函数指针

c - 如何从终端运行 C 代码?

c - 将 char 附加到 C 字符串

c++ - 为什么编译器在编译时不知道局部变量的地址?

c - 使用 fread() 将二进制文件转换为结构体时出现问题

gcc - 如何让编译器生成 "elf32-x86-64"格式的目标文件?

gcc - 编译 OpenCL 应用程序和使用可用编译器选项的正确方法

c++ - 将函数传递给方法原型(prototype)

C中可以通过函数指针调用静态函数吗?