Search code examples
ccastingfunction-pointers

Casting function pointers with arguments of different pointer types


#include <stdio.h>

typedef struct {
    int i;
} A;

void f(A* a) {
    printf("%d\n", a->i);
}

int main() {
    void (*pf)(void*) = (void(*)(void*))&f;
    A a;
    pf(&a); // 1
    ((void(*)(A*))pf)(&a); // 2
}

A function pointer void(*)(A*) is cast to a function pointer void(*)(void*). Then it is called with an argument of type A*.

Is it guaranteed to work correctly when used directly (1)? Or it is needed to cast it back like (2)?


Solution

  • First of all. The casts between pointer to functions with different signatures are allowed by C11 standard, 6.3.2.3p8

    A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer.

    Method 1

    pf(&a); // 1

    No. This is undefined behavior and it is not guaranteed to work. From C11 standard, 6.3.2.3p8:

    ... If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

    Method 2

    ((void(*)(A*))pf)(&a); // 2

    It is fine and defined. because the function with signature void(A*) is called via a pointer to void(A*).

    EDIT

    The compatibility of function types is defined in 6.7.6.3p15:

    For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. ...

    The functions void(void*) and void(A*) are not compatible because types void* and A* are not compatible.