PSkocik PSkocik - 7 days ago 5
C Question

Passing `int (*)(char const*)` where `int (*)(char*)` is expected

I have a function pointer whose function is declared as expecting

char *
arguments.Into it, I'd like to save a pointer to a function declared as taking
char const*
arguments.

I guess I can either use a wrapper or a cast.
Casts seem more straightforward, but are they legal?

Example code below:

static int write_a(char * X){
return 0;
}

static int write_b(char const* X){
return 0;
}
static int wrapped_write_b(char * X){
return write_b(X);
}

typedef int (*write_fn)(char * );

write_fn a = write_a;
write_fn b = wrapped_write_b;
write_fn b1 = (write_fn)write_b; //is this legal?

Answer

This is undefined behavior - You can use a pointer to call a function of another type only if the types are compatible (6.3.2.3/8):

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. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

Two functions have compatible types if (simplified version) they have same return and arguments are compatible (6.7.6.3, Semantics/15):

For two function types to be compatible, both shall specify compatible return types.146) 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.

A const char * is not compatible with a char * (6.7.6.1, Semantics/2):

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

Since const char * and char * are not identically qualified, they are not compatible, and calling write_b through b is undefined behavior.