Perhaps the title isn\'t clear in itself...
I have a function f (provided by some library) that takes as an argument a function pointer of signature void g(int*)
, i
You are right, there's no reason C should disallow that call (other than because the C standard says it should). U(*)(T*)
should be a sub-type of U(*)(const T*)
because int*
is a sub-type of const int*
through substitutability.
Why C does not allow this, I don't know.
As for work-arounds, you can provide a proxy function:
void foo(const int* x) { ... } // <-- the function you want to pass in
void bar(int* x) { foo(x); } // proxy
f(bar); // instead of f(foo)
The fact that using a safe, standard-compliant proxy like this works at all should be proof enough that the call should have been valid in the first place.
You seem to have found something that the compiler writers and standards writers did not account for. From C99 draft n1256, §6.7.5.3 paragraph 15,
corresponding parameters shall have compatible types.
Note that const int *
is not compatible with int *
. However, int *
may be converted to const int *
. From §6.3.2.3, paragraph 2,
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
More sophisticated rules for inferring when it is acceptable to substitute types derived from qualified or unqualified versions of the same type are simply not present in the standard. Therefore, your code is technically in violation of the standard.
My conclusion: It seems to me that this error should be treated as "pedantic" by the compiler: your code does not technically conform to the standard, but the meaning is unambiguous and the code is absolutely safe. Feel free to write a feature request to your compiler vendor. There are plenty of nonconformant practices which do not generate warnings without -pedantic
.
As a final note, I compiled with Clang and the compiler informed me that the warning was pedantic. However, I had not requested pedantic warnings... so there appears to be no way to turn it off.
warning: incompatible pointer types passing 'void (int const *)', expected 'void (*)(int *)' [-pedantic]
Workaround: Use an explicit cast.
void g(const int *);
f((void (*)(int *)) g);