Код четко определен, если все типы параметров представляются самим себе, а все предоставленные аргументы имеют правильный тип.
Если вы хотите получить некоторую меру безопасности типов, вы можете использовать явныйброски или союзы, например
#include <stdio.h>
static double id(double x) { return x; }
static double add2(double x, double y) { return x + y; }
static double add3(double x, double y, double z) { return x + y + z; }
union func
{
double (*as_unary)(double x);
double (*as_binary)(double x, double y);
double (*as_ternary)(double x, double y, double z);
};
static const union func funcs[] = {
{ .as_unary = id },
{ .as_binary = add2 },
{ .as_ternary = add3 }
};
int main(void)
{
printf("id(5.3) = %f\n", funcs[0].as_unary(5.3));
printf("add2(5.3, 6.1) = %f\n", funcs[1].as_binary(5.3, 6.1));
printf("add3(5.3, 6.1, 7.2) = %f\n", funcs[2].as_ternary(5.3, 6.1, 7.2));
return 0;
}