C: Как я могу использовать единый массив указателей функций для функций с переменными параметрами?

Вопрос в значительной степени говорит обо всем.

Я не уверен, как это сделать, и нигде не приближается к чему-либо, что работает.

Вот некоторые примеры функций:

add(int x, int y) {
  return x+y;
}

и

mean(int x1, int y1, int x2, int y2) {
  return (x1 + y1 + x2 + y2) / 4;
}

До сих пор я пытался использовать typedef для обоих, но я не могу понять, как сделать что-то одно из одного типа:

typedef int (*mathfunc2)(int x, int y);
typedef int (*mathfunc4)(int x1, int y1, int x2, int y2);

????? func_table[2] = {add, mean};

Ответ 1

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

Другими словами:

typedef int (*generic_fp)(void);

generic_fp func_table[2] = { (generic_fp)add, (generic_fp)mean };

Затем, чтобы вызвать add, вам нужно вернуть его в нужный тип:

result = ((mathfunc2)func_table[0])(x, y);

Вы можете определить некоторые макросы, если найдете их более приемлемыми:

#define FUNC_2(f, p1, p2) ((mathfunc2)(f))(p1, p2)
#define FUNC_4(f, p1, p2, p3, p4) ((mathfunc4)(f))(p1, p2, p3, p4)

result = FUNC_2(func_table[0], x, y);

Ответ 2

Вы можете использовать Facade Pattern следующим образом:

int add(int x, int y);
int mean(int x1, int y1, int x2, int y2);

typedef int (*operation_fp)(int argc, int* argv);

int add_wrapper(int argc, int* argv) { return add(argv[0], argv[1]); }
int mean_wrapper(int argc, int* argv) { return mean(argv[0], argv[1], argv[2], argv[3]); }

operation_fp func_table[2] = { add_wrapper, mean_wrapper };

Хотя код уродливый, он выполняет эту работу. Вы должны добавить логику проверки в оболочку.

Ответ 3

int (*func[])() = { add, mean };

Ответ 4

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

Однако вы можете определить обе функции с параметрами varargs, чтобы заставить их следовать той же схеме прохождения параметров.

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