Assign a more generic function

Viewed 73

Let's say I have the following C code:

/*  1 */ typedef void (*void_f) (void *);
/*  2 */ typedef void (*int_f)  (int *);
/*  3 */
/*  4 */ void fun_v (void *priv) { }
/*  5 */ void fun_i (int *priv)  { }
/*  6 */
/*  7 */ int main () {
/*  8 */     int        *int_p;
/*  9 */     void       *void_p;
/* 10 */     void_f     vfun_p;
/* 11 */     int_f      ifun_p;
/* 12 */
/* 13 */     int_p   = void_p;
/* 14 */     void_p  = int_p;
/* 15 */     vfun_p  = fun_i;
/* 16 */     ifun_p  = fun_v;
/* 17 */ }

When I compile, I get the following warnings:

15: warning: assignment to ‘void_f’ {aka ‘void (*)(void *)’} from incompatible pointer type ‘void (*)(int *)’ [-Wincompatible-pointer-types]

16: warning: assignment to int_f {aka ‘void (*)(int *)’} from incompatible pointer type ‘void (*)(void *)’ [-Wincompatible-pointer-types]

Note that there are no warnings about lines 13 and 14, although they are assignments of different pointers types. I understand that line 14 should be perfectly valid, since we are assigning a pointer to a "more general type", and maybe 13 could also be considered perfectly valid.

Now, it seems logical to consider void_f also a more general, compatible, type of function than int_f, and there are many valid situations in which an assignment of this type is needed (for example, providing a callback with a private opaque context, although this situation is the inverse).

How can I securely assign compatible non-equal function types without getting a warning?

I don't want to compile with -Wno-incompatible-pointer-types because I still want to be warned when I assign functions which clearly are not compatible, and I also don't want to write a cast like

/* 15 */     vfun_p  = (void (*)(void *))fun_i;
/* 16 */     ifun_p  = (void (*)(int *))fun_v;

because then any mistake in the assignment will be silently shadowed, even with types that clearly are not compatible.

The only option I find is to perform a cast of the argument inside the function:

void fun_i (void *priv) {
    int *num;
    num = (int *)priv;
    /* Rest of code here */
}

But I also don't like this because it has a misleading signature, and I need to add a comment that the void * parameter is in fact an int * parameter.

Any compiler extensions to achieve it?

Any better idea about how to handle this situation?

0 Answers
Related