Укажите функции с разными аргументами, используя один и тот же указатель - PullRequest
1 голос
/ 23 марта 2020

Я пытаюсь построить парсер для заданного ввода, есть 8 возможных команд. Поэтому я решил, что вместо использования уродливой техники блока case switch, подобного этому:

switch(command)
case cmd1:
.... /*call a function that do cmd1*/
case cmd2
..../*call a function that do cmd2*/

я определю в заголовке массив структур, каждый из которых содержит имя функции и указатель на функцию:

typedef struct command_info
{
    char *name;
    void (*func)(int)
};
command_info command_table[] = {{"func1", &func1}, {"func2", &func2} }

Чтобы я мог переключиться на более элегантное:

int i;
for(i = 0; i < COMMAND_TABLE_LENGTH; i++)
  if(!strcmp(command_table[i].name, command))
     command_table[i].func(2);

Моя единственная проблема в том, что функции имеют разные параметры (все возвращают void). Это не проблема для меня, так как я могу проверить, является ли функция func1 или func2 поиск одного аргумента int, например, и если это func3 или func4 поиск двух (все еще более компактный, чем case switch). Но указатель на функцию указывает только на функцию с определенным типом и количеством аргументов. Как я могу сделать универсальный указатель, который может указывать на любую функцию?

1 Ответ

1 голос
/ 23 марта 2020

Но указатель функции указывает только на функцию с определенным типом и количеством аргументов.
Как создать универсальный указатель, который может указывать на любую функцию?

В ограниченном случае OP используйте void (*func)().


. Любой указатель функции может быть преобразован с помощью приведения типа к другому указателю функции и сохранить эквивалентный адрес функции. @ Джонатан Леффлер

int (*foo)(int) = (int (*)(int)) sqrt;
double (*sq)(double) = (double (*)(double)) foo;
printf("%f\n", sq(2));  // prints 1.414214

Указатель функции не должен обеспечивать сигнатуру параметра функции.

// No parameter info
//        vv     
int (*foo)() = (int (*)()) sqrt;

OP has "функции имеют разные параметры (все возвращают void) ", поэтому в коде OP можно использовать ограниченный указатель универсальной функции void (*func)() и потерять проверку параметров.

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.

При вызове .funf() также возникает небольшая проблема: параметры ранжируются ниже * Передаются 1023 *, а также float параметры перед передачей в функцию. Лучше всего убедиться, что параметры не char, float, short, _Bool и c. чтобы избежать проблем с совместимой подписью.


void * - это универсальный объект указатель. Может быть недостаточно кодировать указатель function . Так что это не переносимый кандидат. Нередко размер указателя функции больше sizeof(void*).

...