Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

incompatible pointer type assigning in function pointer usage

Tags:

c

casting

I'm trying to use function pointer in my code, the code is as below.

#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;
}

After compiled the code with "gcc -Wall xxx.c -o xxx -lpthread", the compiler complains with the following message:

func_ptr_test.c:30:16: warning: incompatible pointer types assigning to 'PFUNC' (aka 'void ()(int)') from 'PFUNC (int)' (aka 'void ((int))(int)' [-Wincompatible-pointer-types] info.callback = callback_print;

But, if I change the code from

info.callback = callback_print;

to

info.callback = (PFUNC)callback_print;

No warning message comes out any more. But, even without type casting, I think the "info.callback" has totally the same type with "callback_print", so I'm wondering why the warning message comes out. Does anyone have idea about this?

like image 660
bamb00dark Avatar asked Jan 27 '23 20:01

bamb00dark


1 Answers

Sometimes, exploring what is beneath the surface helps to understand the picture better.

In C, you can pretty much treat the function name as a pointer to that function. Take a look at the example below

#include <stdio.h>

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

In the code snippet above, we could simply use printf() instead of (*printf)(), and it actually is the usual way you would call a function.

Another example is the signal() library function (yes, I am a FreeBSD user), whose definition is given as

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

When you call signal(), the convention is

void
handle(int sig)
{
    ...
}

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

Now, can you see the trick here? Although, signal() is declared to take void (*func)(int) (i.e. a pointer to a function returning void and taking a single int argument), we pass the name of a function of that type as the second argument to signal().

Going back to your question, PFUNC is an alias for a pointer to a function returning void and taking a single int argument. By declaring callback as PFUNC callback you are saying your compiler that, the callback variable will point a function which returns void and takes a single int argument.

So, you should have

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

to match what is expected as the lvalue of your assignment performed by info.callback = callback_print;.

like image 107
fnisi Avatar answered Feb 07 '23 19:02

fnisi