C: Как получить доступ к указателю функции, хранящемуся в пустом указателе (void *)? - PullRequest
0 голосов
/ 29 августа 2018

Смущен тем, как можно получить доступ к указателю функции, хранящемуся в пустом указателе (void *).


Допустим, у вас есть это:

void *functions[] =
{
    &sqrt,         // int ft_sqrt(int nb);
    &power,
    &logN,
    &factorial;
};

// An array of void pointers, each storing a function pointer.

Если бы я хотел получить доступ к функции sqrt, мое предположение было бы следующим:

(int (*)(int)) functions[0](x)

Но мое предположение неверно:

error: called object type 'void *' is not a function or function pointer


Так как можно получить доступ к одной из этих функций?

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Строго говоря, вы не можете. Преобразование между указателем функции и указателем void невозможно. void* никогда не был универсальным типом указателя для указателей функций, только для указателей объектов. Они не совместимы.

На практике любой указатель, скорее всего, будет иметь размер, требуемый адресной шиной системы, поэтому указатели объектов и указатели функций, скорее всего, будут иметь одинаковое представление. Хотя не гарантируется стандартом, и есть некоторые экзотические системы, в которых эта эквивалентность не выполняется. Таким образом, вы можете приводить между void* и указателем на функцию, но в результате произойдет неопределенное поведение. Вы будете полагаться на системные нестандартные расширения.

Немного лучше было бы использовать тип указателя функции, такой как void (*)(void), в качестве общего указателя. Вы можете конвертировать в / из различных указателей функций, что будет зависеть от компилятора (поведение, определяемое реализацией). То есть код по-прежнему будет непереносимым, но, по крайней мере, вы не рискуете аварийно завершить работу программы, вызвав неопределенное поведение.

0 голосов
/ 29 августа 2018

Это вопрос приоритета оператора : оператор вызова функции имеет более высокий приоритет, чем оператор приведения.

Это означает, что ваше выражение (int (*)(int)) functions[0](x) действительно равно (int (*)(int)) (functions[0](x)).

Вам нужно явно добавить скобки в правильные места для приведения указателя: ((int (*)(int)) functions[0])(x).


Гораздо лучшим решением IMO было бы иметь массив указателей на функции , поэтому элементы массива уже имеют правильный тип:

typedef int (*function_ptr)(int);

function_ptr functions[] = { ... };

Тогда кастинг не требуется: functions[0](x).

Тогда вы также будете в безопасности от вопросов, упомянутых в ответе Лундина .

...