简体   繁体   中英

Point to functions with different arguments using the same pointer

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM