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".