Подтвердить что ты не робот

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();
4b9b3361

Ответ 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]);
}