Sorry to revive such an old blog post, but it seems you've made some
erroneous claims, like:
> You can't sort function pointers with qsort().
You can sort function pointers with qsort(), since at no point do you
ever treat function pointers as data pointers, instead you treat
function pointers as data. The compare function passed to qsort()
receives pointers to function pointers, not pointers to functions. If
you've ever sorted strings with qsort(), you know you can't use strcmp()
as your compare function and need to resort to using a function like
cmpstringp() from the qsort(3) man-page:
static int
cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference. */
return strcmp(*(const char **) p1, *(const char **) p2);
}
I've attached a small program which sorts function pointers and will not
emit any warnings even if compiled with -pedantic, -Wall or whatever.
You also claim
> You can't even treat the function pointer as a blob of data to> manipulate manually since there's no safe way to make a regular> pointer to it.
which is wrong for a similar reason: you can take a pointer to the
function pointer (say `int (**p)()`), cast it to `char *` and treat it
as a blob of data of size sizeof(int (*)()). Unless you were refering to
treating the function data as a blob of data, in which case you'd be
right.
If there's anything wrong with my statements it's that they weren't strong
enough. I followed up 6 years later with a more general post:
You Can't Always Hash Pointers in C
https://nullprogram.com/blog/2016/05/30/
Though this stuff is hypothetical and not worth pontification. Nearly all
implementations have straightforward pointer representations, and the
practical, interesting issues involve pointer provenance, which the
standard barely touches.
> You can sort function pointers with qsort() [...] instead you treat > function pointers as data
As far as the standard is concerned, this will not necessarily work, and
pointers, object or function, are not meaningfully sortable. There are few
constraints regarding pointer representation. Two pointers comparing equal
with == may have memory representations that compare unequal with memcmp
(ignored bits, etc.). The sorted array may not correspond with ==, and
certainly not less-than and greater-than (which are undefined behavior
anyway).
> I've attached a small program which sorts function pointers
That's a clever workaround, but it's not really sorting pointers. It's
sorting by array index, with a terribly inefficient lookup to map pointers
onto indices. Per the above article, there's no way to improve the lookup
in a conforming program due to a lack of pointer semantics required for
map building.
In practice, you'd just depend on implementation-defined behavior and call
it a day, making the exercise here academic.
> take a pointer to the function pointer (say `int (**p)()`), cast it to > `char *`
The standard explicitly says that it is undefined behavior if a "pointer
to a function is converted to a pointer to an object" making this cast
forbidden. POSIX requires object/function pointer compatibility due to
dlsym, and so C implementations on POSIX must define the behavior, making
it defined in practice even beyond POSIX. But as far as C is concerned
it's non-conforming to rely on any particular cast behavior.
> You Can't Always Hash Pointers in C> https://nullprogram.com/blog/2016/05/30/
That's an interesting follow up, especially the part about memset and
calloc. I've always considered pointer-type members in a struct obtained
from calloc() to be NULL, but I guess they technically need to be
initialized.
> The standard explicitly says that it is undefined behavior if a> "pointer to a function is converted to a pointer to an object" making> this cast forbidden.
I think you're confusing converting a "pointer to a function to a
pointer to an object" with converting a "pointer to a pointer to a
function (which to my knowledge already is a pointer to an object) to a
pointer to a character type", which you can do just fine if you're just
interpreting the bytes of the object (§6.3.2.3¶7).
In any case, the reason you don't get a meaningful value when
interpreting the bytes from function pointers is not that "Function
Pointers are Special", but rather that the bytes from a
function/object/void pointer have no meaningful value, it's the same
reason why "You Can't Always Hash Pointers in C."