I am trying to build a parser to a given input, there are 8 possible commands. So I figured that instead of using the ugly technique of a case switch
block like that:
switch(command)
case cmd1:
.... /*call a function that do cmd1*/
case cmd2
..../*call a function that do cmd2*/
I will define in a header an array of structs, each one contains the name of the function, and a pointer to a function:
typedef struct command_info
{
char *name;
void (*func)(int)
};
command_info command_table[] = {{"func1", &func1}, {"func2", &func2} }
So that I can switch to the more elegant:
int i;
for(i = 0; i < COMMAND_TABLE_LENGTH; i++)
if(!strcmp(command_table[i].name, command))
command_table[i].func(2);
My only problem is, that the functions have different parameters (all return void). This is not a problem for me since I can check if the function is func1
or func2
search for one int argument for example, and if it is func3
or func4
search for two (still more compact than case switch
). But the function pointer only points to a function with a certain type and amount of arguments. How can I make a universal pointer that can point to any function?
But the function pointer only points to a function with a certain type and amount of arguments.
How can I make a universal pointer that can point to any function?
In OP's limited case, use void (*func)()
.
Any function pointer can be converted with a type cast to another function pointer and retain an equivalent function address. @Jonathan Leffler
int (*foo)(int) = (int (*)(int)) sqrt;
double (*sq)(double) = (double (*)(double)) foo;
printf("%f\n", sq(2)); // prints 1.414214
A function pointer need not provide a function parameter signature.
// No parameter info
// vv
int (*foo)() = (int (*)()) sqrt;
OP has "functions have different parameters (all return void)", so in OP's case code could use a limited universal function pointer of void (*func)()
and lose parameter checking.
typedef struct {
char *name; // suggest const char *name
void (*func)(); // no parameter info nor checking
} command_info;
char buf[100];
// void setbuf(FILE * restrict stream, char * restrict buf);
command_info fred = { "my_setbuf", setbuf };
// Both compile, 2nd is UB.
fred.func(stdin, buf); // No parameter checking.
fred.func(0); // No parameter checking.
Code also incurs a subtle issue when calling .funf()
: the parameters ranking lower than int/unsigned
are promoted as well as float
parameters before passed to the function. Best to make certain the parameters are not char, float, short, _Bool
etc. to avoid compatible signature issues.
void *
is a universal object pointer. It may be insufficient to encode a function pointer. So it is not a portable candidate. It is not uncommon for the size of a function pointer to be wider than sizeof(void*)
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.