0

Why do i need to remove the function pointer casting to use the function as shown below ?

This Compiles:

#include <stdio.h>

int print_int(int i){
    printf("%d", i);
    return i;
}
typedef int (*print_int_func) (int);

int main(){
    void** p = malloc(1*sizeof(print_int_func*));
    p[0] = (print_int_func*)print_int;

    ((print_int_func)p[0])(2); // This Compiles
    ((print_int_func*)p[0])(2); // This does NOT
    
    return 0;
}

  • If you're assigning to `void**`, you need to use `malloc(1 * sizeof(void*))`. The argument to `sizeof` is always the destination type with one less `*`. – Barmar Dec 11 '20 at 22:44
  • @Barmar I am trying to store functions inside a void pointer array. Currently it works. However I am trying to understand why the pointer declaration is such. – Iwata Kurosawa Dec 11 '20 at 22:48
  • See https://stackoverflow.com/questions/3941793/what-is-guaranteed-about-the-size-of-a-function-pointer there's no guarantee that a `void*` can hold a function pointer. – Barmar Dec 11 '20 at 22:50
  • In general you don't dereference function pointers. – Barmar Dec 11 '20 at 22:50
  • @Barmar: They should not be using `void *` in the first place; function pointers are different from object pointers, and `void *` is not a generic type for function pointers. Additionally, its preferable to use the actual identifier being assigned, with an `*`, for the `sizeof`, rather than repeating the type: `AnyType *p = malloc(NumberOf * sizeof *p);`. – Eric Postpischil Dec 11 '20 at 22:51

1 Answers1

1

The declaration typedef int (*print_int_func) (int); declares print_int_func to be a pointer to a specific type of function. So (print_int_func)p[0] casts p[0] to such a pointer to a function, but (print_int_func*)p[0] casts p[0] to a pointer to a pointer to a function. Thus, the result is a pointer to an object (that object being a pointer to a function). Since it is an object, not a function (or pointer to a function), it cannot be called like a function.

Additionally, avoid using void * for pointers to functions. void * is a pointer to an object, and the C standard does not define conversions between pointers to objects and pointers to functions. To create a “generic” pointer to a function, simply choose any function type and use a pointer to that type:

  • Convert to the chosen type when storing the pointer.
  • Convert to the actual function type when calling the function type.

For example, you can declare an arbitrary type:

typedef void (*CommonFunctionPointer)(void);

and make an array of them:

CommonFunctionPointer *p = malloc(N * sizeof *p);,

and then you can store any function pointer in the array:

p[i] = (CommonFunctionPointer) print_int;

and use a pointer from the array by casting it back to its correct type:

((int (*)(int)) p[i])(2);.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thank You ! So `(print_int_func)p[0]` casts p[0] into a function so it can be called. – Iwata Kurosawa Dec 11 '20 at 23:02
  • In relation to object vs function pointers, what is the rationale behind it ? Is it because C does not give any solid guarantees on it's integrity during usage ? – Iwata Kurosawa Dec 11 '20 at 23:12
  • 1
    @IwataKurosawa: Specifically, it casts `p[0]` to a pointer to a function. The function call operator (parentheses after an expression) only calls pointers to functions. When you write a function call using a function name, like `sin(x)`, the function is automatically converted to a pointer. – Eric Postpischil Dec 11 '20 at 23:12
  • 1
    (This is true even if the function is created by dereferencing a pointer. If you have a `q` that points to a function and write `(*q)(x)`, `*q` is a function, but it is automatically converted to a pointer to the function. And then you can apply `*` again. `(**q)(x)` calls the same function. So does `(******q)(x)`.) – Eric Postpischil Dec 11 '20 at 23:12
  • 1
    @IwataKurosawa: Object pointers and function pointers are different because in some computers, their addresses were managed differently, and the C standard wanted to allow C to be used on a wide variety of computers. – Eric Postpischil Dec 11 '20 at 23:13