Прототип функции с параметром void*

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

void processA(A *);
void processB(B *);

Существует ли тип указателя на функцию, который мог бы содержать указатель на любую функцию без приведения? Я пытался использовать

typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};

но это не сработало (компилятор жалуется на несовместимую инициализацию указателя).

Редактировать: другая часть кода будет перебирать записи Ps, не зная типов. Этот код будет передавать символ * в качестве параметра. Как это:

Ps[i](data_pointers[j]);

Редактировать: Спасибо всем. В конце я, вероятно, буду использовать что-то вроде этого:

void processA(void*);
void processB(void*);

typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};

...

void processA(void *arg)
{
  A *data = arg;
  ...
}

3 ответа

Решение

Это можно сделать без приведения с помощью объединения:

typedef struct A A;
typedef struct B B;

void processA(A *);
void processB(B *);

typedef union { void (*A)(A *); void (*B)(B *); } U;

U Ps[] = { {.A = processA}, {.B = processB} };

int main(void)
{
    Ps[0].A(0); // 0 used for example; normally you would supply a pointer to an A.
    Ps[1].B(0); // 0 used for example; normally you would supply a pointer to a B.
    return 0;
}

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


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

typedef struct A A;
typedef struct B B;

void processA(A *);
void processB(B *);

typedef void (*processor_t)();

void processAproxy(char *A) { processA(A); }
void processBproxy(char *B) { processB(B); }

processor_t Ps[] = { processAproxy, processBproxy };

int main(void)
{
    char *a = (char *) address of some A object;
    char *b = (char *) address of some B object;
    Ps[0](a);
    Ps[1](b);
    return 0;
}

я использовал char * выше, так как вы заявили, что используете его, но я бы вообще предпочел void *,

Если ты typedef void (*processor_t)(); тогда это скомпилируется в C. Это потому, что пустой список аргументов оставляет число и типы аргументов функции неуказанными, поэтому этот typedef просто определяет тип, который является "указателем на функцию, возвращающую void, принимая неопределенное количество аргументов неуказанного тип."

Редактировать: Кстати, вам не нужны амперсанды перед именами функций в списке инициализатора. В C имя функции в этом контексте превращается в указатель на функцию.

Это работает, если вы разыгрываете их

processor_t Ps[] = {(processor_t)processA, (processor_t)processB};

Кстати, если ваш код связан с этим типом вещей и switchПовсюду, чтобы выяснить, какую функцию вам нужно вызвать, вы можете взглянуть на объектно-ориентированное программирование. Лично мне это не очень нравится (особенно C++...), но он отлично справляется с удалением такого рода кода с помощью виртуального наследования.

Другие вопросы по тегам