You're right to wonder - passing it an argument that could not be
assigned to an object of the declared type of the parameter would be a
constraint violation (6.5.2.2p2). Such an assignment would be permitted
only if
"... (considering the type the left operand would have after lvalue
conversion) both operands are pointers to qualified or unqualified
versions of compatible types, and the type pointed to by the left has
all the qualifiers of the type pointed to by the right." (6.5.16.1p1).
In general, using incompatible function types would be seriously
problematic. However, in this particular case, the only difference is in
the location of the 'const' qualifier, so the issue gets a little more
subtle.
The 'const' that appears in a parameter declared "void * const" is
ignored for purposes of determining the compatibility of the function
types (6.7.6.3p15). However, the 'const' that appears in "const void*"
is not ignored, so those parameter types are not compatible (6.7.6.1p2),
rendering the function types not compatible (6.7.6.3p15).
It would be legal to call qsort() without #include <stdlib.h>. If you do
that, you have to provide a declaration for it, but that declaration
could be a K&$ style declaration, which would qualify as compatible with
the definition of qsort(). In that case, there is no compile-time
compatibility check. Instead, if the value passed as the fourth argument
of qsort was not compatible with int(*)(const void*, const void*), the
behavior of the call to qsort() would be undefined (6.5.2.2p6).
In practice, I would not expect the undefined behavior of such a call to
be problematic unless the function declared "int(*)(void *const, void
*const) actually took advantage of that fact by attempting to write
through the pointers, which this one doesn't, so it might work despite
the nominal incompatibility. However, I wouldn't recommend counting on that.