ISO C Void * и указатели функций
Во время следующих уроков и чтения о указателях функций я узнал, что, очевидно, назначение указателя void указателю на функцию в ISO C undefined, есть ли способ разрешить предупреждение, которое я получаю во время компиляции (например, лучший способ его кодирования) или я должен просто игнорировать его?
Внимание:
ISO C forbids assignment between function pointer and 'void *' [-pedantic]
Пример кода:
void *(*funcPtr)();
funcPtr = GetPointer();
GetPointer - это функция, которая возвращает указатель void E.G.
void *GetPointer();
Ответы
Ответ 1
Нет. Компилятор прав, и вы тоже: на C89 и C99 вы не можете конвертировать между указателями данных (которые void *
) и указателями на функции, поэтому единственный способ разрешить предупреждение - вернуть указатель функции из этой функции.
(Обратите внимание, что на практике это работает, несмотря на предупреждение, и даже там эта несогласованность в стандартной библиотеке - функция dlsym()
используется для получения указателей на функции, но возвращает void *
- поэтому по существу вы можете игнорируйте предупреждение. Он будет работать, хотя, строго говоря, поведение undefined здесь.)
Ответ 2
В tlpi-book Я нашел этот трюк очень интересным:
#include <dlfcn.h>
int
main(int argc, char *argv[])
{
...
void (*funcp)(void); /* Pointer to function with no arguments */
...
*(void **) (&funcp) = dlsym(libHandle, argv[2]);
}
Ответ 3
Я столкнулся с этой проблемой с помощью glib. Структуры данных Glib, такие как GSList, обычно имеют поле, называемое void * data. Я хотел сохранить функции в списке и получил кучу ошибок, подобных этому:
warning: ISO C forbids passing argument 2 of ‘g_slist_append’ between function pointer and ‘void *’ [-pedantic]
В этом примере создается куча предупреждений с использованием gcc -Wall -ansi -pedantic
typedef int (* func) (int);
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
func f;
functions = g_slist_append(functions, mult2);
f = (func *) functions->data;
printf("%d\n", f(10));
return 0;
}
Итак, я завернул функцию в структуру и все предупреждения ушли:
struct funcstruct {
int (* func) (int);
};
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
struct funcstruct p;
p.func = mult2;
functions = g_slist_append(functions, &p);
p = * (struct funcstruct *) functions->data;
printf("%d\n", p.func(10));
return 0;
}
Можно утверждать, что это довольно много лишнего кода, чтобы несколько предупреждений исчезли, но мне не нравится, когда мой код генерирует предупреждения. Кроме того, приведенные выше примеры игрушек. В реальном коде, который я пишу, оказывается весьма полезным обернуть список функций в структуре.
Мне было бы интересно услышать, если это проблематично или если есть лучший способ сделать это.
Ответ 4
На основе ответа @WeinanLi, но с помощью вспомогательной функции для ясности:
#include <dlfcn.h>
/* Pointer to function with no arguments */
typedef void (functor_t*)(void);
void load_symbol( functor_t* functor, void* dl_handle, const char* symbol_name ) {
*(void**)functor = dlsym( dl_handle, symbol_name );
}
int
main(int argc, char *argv[])
{
// [...]
functor_t funcp;
// [...]
load_symbol( &funcp, libHandle, argv[2]);
}