присвоение несовместимого типа указателя при использовании указателя функции

Я пытаюсь использовать указатель на функцию в своем коде, код такой, как показано ниже.

#include <stdio.h>
#include <pthread.h>

typedef void (*PFUNC)(int);

typedef struct tag_FUNC_INFO_S
{
    PFUNC callback;
    int   index;
} FUNC_INFO_S;

PFUNC callback_print(int index)
{
    printf("[callback] index = %d\n", index);
    return NULL;
}

void thread_test(FUNC_INFO_S *info)
{
    info->callback(info->index);

    pthread_exit(NULL);
}

int main()
{
    pthread_t tid;

    FUNC_INFO_S info;
    info.callback = callback_print;
    info.index    = 777;

    pthread_create(&tid, NULL, (void *)thread_test, &info);

    printf("main printing\n");

    return 0;
}

После компиляции кода с помощью «gcc -Wall xxx.c -o xxx -lpthread» компилятор сообщает следующее сообщение:

func_ptr_test.c: 30: 16: предупреждение: несовместимые типы указателей, назначаемые для 'PFUNC' (aka 'void () (int)') из 'PFUNC (int)' (aka 'void ( (int )) (int) '[-Wincompatible-указатели-типы] info.callback = callback_print;

Но если я изменю код с

info.callback = callback_print;

to

info.callback = (PFUNC)callback_print;

Предупреждающее сообщение больше не появляется. Но, даже без приведения типов, я думаю, что «info.callback» имеет тот же тип, что и «callback_print», поэтому мне интересно, почему появляется предупреждающее сообщение. Кто-нибудь знает об этом?


person bamb00dark    schedule 02.07.2018    source источник
comment
Я верю: PFUNC callback_print(int index) - ›void callback_print(int index)   -  person Christian Gibbons    schedule 02.07.2018
comment
функции, используемые как потоки, ДОЛЖНЫ иметь синтаксис: void * functionName( void *) Функции ваших потоков не имеют этого синтаксиса   -  person user3629249    schedule 03.07.2018
comment
ближе к концу функции main() отсутствует оператор (ы): int *status = NULL; pthread_join( tid, &status );   -  person user3629249    schedule 03.07.2018
comment
первые несколько строк thread_test() должны быть: void *thread_test( void *param) { FUNC_INFO_S info = *( FUNC_INFO*)param;   -  person user3629249    schedule 03.07.2018
comment
настоятельно рекомендую заменить: gcc -Wall xxx.c -o xxx -lpthread на gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 xxx.c -o xxx -lpthread   -  person user3629249    schedule 03.07.2018


Ответы (3)


Иногда изучение того, что находится под поверхностью, помогает лучше понять картину.

В C вы можете рассматривать имя функции как указатель на эту функцию. Взгляните на пример ниже

#include <stdio.h>

int main() {
    (*printf)("test\n");
    return 0;
}

В приведенном выше фрагменте кода мы могли бы просто использовать printf() вместо (*printf)(), и на самом деле это обычный способ вызова функции.

Другой пример - функция библиотеки signal () (да, я пользователь FreeBSD), определение которого дано как

 void
 (*signal(int sig, void (*func)(int)))(int);

Когда вы вызываете signal(), соглашение

void
handle(int sig)
{
    ...
}

int main(int argc, char **argv)
{
    (void) signal(SIGUSR1, handle);
    ...
}

Теперь вы видите фокус здесь? Хотя объявлено, что signal() принимает void (*func)(int) (т.е. указатель на функцию, возвращающую void и принимающую единственный аргумент int), мы передаем имя функции этого типа в качестве второго аргумента в signal().

Возвращаясь к вашему вопросу, PFUNC - это псевдоним для указателя на функцию, возвращающую void и принимающую единственный аргумент int. Объявляя callback как PFUNC callback, вы говорите своему компилятору, что переменная callback будет указывать на функцию, которая возвращает void и принимает единственный аргумент int.

Итак, у вас должно быть

void callback_print(int index) /* now you have a void ()(int) */
{
    printf("[callback] index = %d\n", index);
}

чтобы соответствовать ожидаемому lvalue вашего задания, выполняемого info.callback = callback_print;.

person fnisi    schedule 03.07.2018

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

void callback_print(int index)
{
    printf("[callback] index = %d\n", index);
}
person dbush    schedule 02.07.2018

Вы неправильно понимаете указатель на функцию.

Вы можете изменить свой

PFUNC callback_print(int index) 

прототип как

void callback_print(int index) 

И все должно быть хорошо. Компилятор недоволен тем, что

PFUNC callback_print(int index) 

прототип - void (* (*)(int))(int), но тип PFUNC - void(*)(int), поэтому ваш тип возврата void(*)(int), а не void

person Winnie    schedule 28.05.2021