True, but if you know f[0] isn't what it is declared to be, why use an
array rather than a struct comprising the correct function pointer types?
Because the array is a generic data type which can be indexed.
Consider the following totally hypothetical* example:
static struct {
char *name; /* the name */
int (**real)(void); /* the underlying syscall */
int (*dummy)(void); /* the always-fails form */
int (*wrapper)(void); /* the wrapper from guts/name.c */
} pseudo_functions[] = {
{ /* int open(const char *path, int flags, ...); */
"open",
(int (**)(void)) &real_open,
(int (*)(void)) dummy_open,
(int (*)(void)) wrap_open
},
{ /* char * getcwd(char *buf, size_t size); */
"getcwd",
(int (**)(void)) &real_getcwd,
(int (*)(void)) dummy_getcwd,
(int (*)(void)) wrap_getcwd
},
[...]
{ NULL, NULL, NULL, NULL },
};
This table is usable despite the fact that virtually none of
the functions in it are actually functions taking void and returning
int. However, it can be used to have a single loop go over the
list processing the things in it appropriately... Consider also
a hypothetical table of operators for an interpreter, which might
declare a consistent function type, then cast functions before
calling them accordingly (untested, mighta typed this wrong):
switch (e->operands) {
case 1:
e = (expr *()(expr *))(e->fn)(e->operand1);
break;
case 2:
e = (expr *()(expr *, expr *))(e->fn)(e->operand1, e->operand2);
break;
}
While most trivial test programs have no real reason to cast function
pointers, many more interesting uses really do benefit hugely from being
able to have a single type which is used to hold pointers to many different
types of functions, which are then suitably cast before calling them.
-s
[*] Not hypothetical at all, and has never once been the cause of any
bugs out of millions of runs.