-1

I am having difficulty in passing a function as void* with its argument also 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;
}

The error is:

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);
         ^~~~~

Any suggestions of how to actually pass a function as an argument whose type is void*?

Thank you @2501, but I am getting the following error.

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){       

when I am writing the code as:

 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;
    }
sephora
  • 21
  • 1
  • 7

2 Answers2

0

First I want to say that what you are doing is very, very bad. You are converting a function that takes and returns an integer to a function to that takes and returns a void*, then inside your function (hello) you are saving the returned value as an int*, and continue to return the int* cast to a void*, which you finally cast back to int (without freeing the memory, I may add).

The first thing you need to know is that you can cast anything to a void pointer. This is one of the reasons people stray from them. Personally, I love playing with hacky code and trying to figure things out, maybe that is what you are doing. But please, please, please don't include this kind of code in any projects or in your work, especially if you are collaborating.

Now, back to void pointers. ANYTHING can be a void pointer. I can't stress this enough. For example,

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

is completely valid (though not good) code. You can also cast non-pointer types to a void pointer.

Calling the function: int *value = (int*) hello( (void* (*)(void*))calc, (void*)arg ); you need to cast the function and the argument to the correct pointer type. Notice that I don't use &calc or &arg, because we don't need to. Remember, we can cast anything to void*, so why bother dealing with referencing and dereferencing if we don't have to? The cast for calc can be simplified to (void*)calc, I just use the full cast above to make it clear what is happening.

The hello Function

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

All I changed here was the name of the function (you don't want to name a function pointer the same name as an actual function, it could give unexpected results).

If you want the code to be portable for different types, I would recommend modifying it a little bit:

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

and calling it from main like so:

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

The aditional argument specifies that the function will return sizeof(int) bytes, so you know that you are getting the correct amount of data back.

Finally, in your main you shouldn't immediately dereference the pointer, but rather take the value and free the memory, to avoid memory leaks.

Jacob H
  • 864
  • 1
  • 10
  • 25
0

Your code has several errors, but one is critical: converting a function pointer to a non-compatible type and calling it. This happens in the function hello when you call the parameter calc, which has the type void*(*)(void*) converted from an incompatible type int(*)(int).
This call will result in undefined behavior.

The correct solution for passing the function pointer is to use the proper type,
in this case: int(*)(int).

No memory needs to be allocated as the return value of the call to the function pointer can be stored in the same variable:

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

    return op;
}

If you insist on using the type void*(*)(void*) for the first parameter in the function hello, then you must convert the parameter back to its correct type:

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

    return op ;
}
2501
  • 25,460
  • 4
  • 47
  • 87