将函数作为void *传递,其参数也为void *

时间:2016-11-03 01:11:28

标签: c void-pointers

我很难将void*函数传递给它的参数void*

#include <stdlib.h>

void* hello(void* (*calc)(void *), void* op){
    int val = *(int *) op;
    int* retval = malloc(sizeof(int));
    *retval = calc(val);
    return retval;
}


int calc(int b){
    int a = 5;
    int sum = a+b;
    return sum;
}

int main(){
    int arg = 4;
    int value = *(int*) hello(&calc,&arg);
    return 0;
}

错误是:

40392282.c: In function ‘hello’:
40392282.c:6:20: warning: passing argument 1 of ‘calc’ makes pointer from integer without a cast [-Wint-conversion]
     *retval = calc(val);
                    ^~~
40392282.c:6:20: note: expected ‘void *’ but argument is of type ‘int’
40392282.c:6:13: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
     *retval = calc(val);
             ^
40392282.c: In function ‘main’:
40392282.c:19:31: warning: passing argument 1 of ‘hello’ from incompatible pointer type [-Wincompatible-pointer-types]
     int value = *(int*) hello(&calc,&arg);
                               ^
40392282.c:3:7: note: expected ‘void * (*)(void *)’ but argument is of type ‘int (*)(int)’
 void* hello(void* (*calc)(void *), void* op){
       ^~~~~
40392282.c:19:9: warning: unused variable ‘value’ [-Wunused-variable]
     int value = *(int*) hello(&calc,&arg);
         ^~~~~

有关如何将函数实际传递为类型为void*的参数的任何建议吗?

谢谢@ 2501,但我收到以下错误。

hello.c: In function ‘hello’:
hello.c:12:18: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
 int(*calc)(int) =calc_call;
                  ^
hello.c: In function ‘main’:
hello.c:34:35: warning: passing argument 1 of ‘hello’ from incompatible pointer type [-Wincompatible-pointer-types]
   int value = *(int *) hello(&calc,&arg);
                                   ^
hello.c:10:7: note: expected ‘void * (*)(void *)’ but argument is of type ‘int (*)(int)’
 void* hello(void* (*calc_call)(void *), void* op){       

当我编写代码时:

 void* hello(void* (*calc_call)(void *), void* op){
        int* const integer = op;
        int(*calc)(int) =calc_call;
        *integer=calc(*integer);
        return op;
    }


    int calc(int b){
        int a = 5;
        int sum = a+b;
        return sum;
    }

    int main(){
        int arg = 4;
        int value = *(int*) hello(&calc,&arg);
        return 0;
    }

2 个答案:

答案 0 :(得分:0)

首先,我想说你正在做的事情非常非常糟糕。您正在转换一个函数,该函数接受并返回一个函数,该函数接受并返回一个void *,然后在函数内(hello)将返回值保存为int *,并继续返回int * cast to一个void *,你最终将它强制转换为int(不释放内存,我可以添加)。

您需要知道的第一件事是您可以将任何内容转换为void指针。这是人们偏离它们的原因之一。就个人而言,我喜欢玩hacky代码并尝试解决问题,也许这就是你正在做的事情。但请,请不要在任何项目或工作中包含此类代码,特别是如果您正在合作。

现在,回到无效指针。任何东西都可以是一个无效指针。我不能强调这一点。例如,

int *****arr; // 5D array
void* arr_ptr = (void*)arr;

完全有效(但不是很好)代码。您还可以将非指针类型强制转换为void指针。

调用函数: int *value = (int*) hello( (void* (*)(void*))calc, (void*)arg );您需要将函数和参数强制转换为正确的指针类型。请注意,我不使用&calc&arg,因为我们不需要。请记住,我们可以将任何内容转换为void *,如果我们不需要,为什么还要处理引用和解除引用? calc的强制转换可以简化为(void*)calc,我只需使用上面的完整演员来清楚说明发生了什么。

你好功能

void* hello(void* (*func)(void *), void* op)
{
    int* retval = malloc(sizeof(*retval));
    *retval = (int)func(op);
    return retval;
}

我在这里更改的是函数的名称(您不希望将函数指针命名为与实际函数相同的名称,它可能会产生意外结果)。

如果您希望代码可以移植到不同类型,我建议稍微修改一下:

void* hello(void* (*func)(void *), void* op, int size)
{
    void** retval = malloc(size);
    *retval = func(op);
    return retval;
}

并从主处调用它:

 int *value = (int*) hello((void*)calc, (void*)arg, sizeof(int));

aditional参数指定函数将返回sizeof(int)个字节,因此您知道正在获取正确数量的数据。

最后,在你的主文件中你不应该立即取消引用指针,而是取值并释放内存,以避免内存泄漏。

答案 1 :(得分:0)

您的代码有几个错误,但一个是关键的:将函数指针转换为不兼容的类型并调用它。调用参数calc时,函数hello会发生这种情况,参数calc的类型void*(*)(void*)由不兼容的类型int(*)(int)转换而来。
 此调用将导致未定义的行为。

传递函数指针的正确解决方法是使用正确的类型,
在这种情况下:int(*)(int)

不需要分配内存,因为对函数指针的调用的返回值可以存储在同一个变量中:

void* hello( int( *calc)( int ) , void* op )
{
    int* const integer = op ;
    *integer = calc( *integer );

    return op;
}

如果你坚持在函数hello中使用类型void*(*)(void*)作为第一个参数,那么你必须将参数转换回正确的类型:

void* hello( void*( *calc )( void* ) , void* op )
{
    int* const integer = op ;
    int ( *correct )( int ) = ( ( int )( * )( int ) )calc;
    *integer = correct( *integer );

    return op ;
}