The fact that you can use a wrapper to avoid the warning should show that there isn't a deep technical reason:
void bar(const char *p) { /* ... */ }
void bar_w(char *p) { bar(p); } /* wrapper */
foo(bar_w); /* instead of foo(bar) */
This is based on then well known fact that you can use a pointer-to-T (for any type T) where a pointer-to-const-T is expected (as in your first example).
The warning is due to §6.7.5.3.15 - Function declarators (from ISO/IEC 9899:TC3):
For two function types to be compatible...
[cut]
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.
and const char *p
is not compatible with char *p
.
Anyway the compiler issues just a warning (not an error): maybe the programmer is using the wrong function (with a similar signature) and the warning can help to identify the situation.
If everything is ok an explicit cast / a wrapper function can rapidly resolve the "nuisance".
EDIT
it appears that char *p
is compatible with const char *p
, just not the other way around
char *p
can be implicitly converted to const char *p
(§6.3.2.3):
For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal
(in other words, const
, volatile
and restrict
qualifiers can be added. The original pointer and the result compare equal. See also Implicit conversions).
E.g.
char n;
const char *p = &n; /* &n has type char * */
This doesn't mean that const char *
(a pointer to const-qualified char) is compatible with char *
(pointer to char):
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types
(§6.7.5.1)
The pointer are identically qualified (they aren't qualified!) but they aren't pointer to compatible types (const char
is not compatible with a char
).