简体   繁体   中英

ISO C Void * and Function Pointers

While following some tutorials and reading about function pointers I learned that evidently assigning a void pointer to a function pointer in ISO C is undefined, is there any way to resolve the warning I receive during compile time (eg a better way of coding it) or should I just ignore it?

Warning:

ISO C forbids assignment between function pointer and 'void *' [-pedantic]

Example Code:

void *(*funcPtr)();
funcPtr = GetPointer();

GetPointer is a function that returns a void pointer EG

void *GetPointer();

In tlpi-book I found this trick very interesting:

#include <dlfcn.h>

int
main(int argc, char *argv[])
{
    ...
    void (*funcp)(void);        /* Pointer to function with no arguments */
    ...
    *(void **) (&funcp) = dlsym(libHandle, argv[2]);
}

No. The compiler is right, and you too: in C89 and C99, you can't convert between data pointers (which void * is) and function pointers, so the only way for resolving the warning is returning a function pointer from the function.

(Note, however, that in practice this works despite the warning, and even there's this inconsistency in the standard library - the dlsym() function is used for obtaining function pointers, but it returns void * - so essentially you can ignore the warning. It will work, although strictly speaking the behavior is undefined here.)

I encountered this problem using glib. Glib data structures, such as GSList usually have a field called void *data. I wanted to store functions in a list and got a bunch of errors similar to this:

warning: ISO C forbids passing argument 2 of ‘g_slist_append’ between function pointer and ‘void *’ [-pedantic]

This example generates a bunch of warnings using 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;
}

So I wrapped the function in a struct and all the warnings go away:

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

It's arguable that this is quite a bit of extra code to make a few warnings disappear, but I don't like my code to generate warnings. Also, the above are toy examples. In the real code I'm writing, it turns out to be quite useful to wrap the list of functions in a struct.

I'd be interested to hear if this is problematic or if there's a better way of doing it.

Based on @WeinanLi answer, but using an auxiliary function for clarity:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM