Page 1 of 2 12 LastLast
Results 1 to 10 of 20

Thread: Type casting a void function pointer in C

  1. #1
    Join Date
    Nov 2009
    Beans
    41

    Type casting a void function pointer in C

    I'm writing a program that has:

    A function that returns char*
    A function that returns int
    An array of two void function pointers

    I made the function pointer void because I want to be able to assign the char* and int functions to it by typecasting the void pointer to int and char* respectively. Here's the code:

    Code:
    #include <stdio.h>
    #include <malloc.h>
    
    typedef union {
        int intData;
        char *charData;
    } dataUnion;
    
    void (*funcArray[2])(dataUnion param);
    
    int func1(dataUnion param) {
        return param.intData;
    }
    
    char *func2(dataUnion param) {
        return param.charData;
    }
    
    int main(void)
    {
        int a;
        char *b;
        
        dataUnion c;
    
        c.intData = 0;
        c.charData = "foobar";
    
        funcArray[0] = malloc(sizeof(int));
        funcArray[0] = (int (*)(dataUnion)) funcArray[0];
        funcArray[0] = &func1;
    
        funcArray[1] = malloc(sizeof(char*));
        funcArray[1] = (char* (*)(dataUnion)) funcArray[1];
        funcArray[1] = &func2;
    
        a = (*funcArray[0])(c);
        b = (*funcArray[1])(c);
    
        printf("%d\n", a);
        printf("%s\n", c);
    
        return 0;
    }
    I have these errors:
    Code:
    executors.c: In function ‘main’:
    executors.c:30:15: warning: assignment from incompatible pointer type [enabled by default]
    executors.c:33:15: warning: assignment from incompatible pointer type [enabled by default]
    executors.c:35:4: error: void value not ignored as it ought to be
    executors.c:36:5: error: void value not ignored as it ought to be
    make: *** [executors] Error 1
    I'm still learning the ropes of C, so excuse me if I've done something foolish in the code, or if I'm missing something obvious.

    Thanks!

  2. #2
    Join Date
    Nov 2005
    Location
    Bordeaux, France
    Beans
    11,294
    Distro
    Ubuntu 12.04 Precise Pangolin

    Re: Type casting a void function pointer in C

    Quote Originally Posted by Datweakfreak View Post
    I made the function pointer void because I want to be able to assign the char* and int functions to it by typecasting the void pointer to int and char* respectively.
    You can do that all right, but you do need to cast at every step. Both when storing and accessing the pointers. This is not exactly the kind of thing that I would do to "learn the ropes of C", but whatever. Here goes:

    Code:
    #include <stdio.h>
    #include <malloc.h>
    
    typedef union {
        int intData;
        char *charData;
    } dataUnion;
    
    void (*funcArray[2])(dataUnion param);
    
    int func1(dataUnion param) {
        return param.intData;
    }
    
    char *func2(dataUnion param) {
        return param.charData;
    }
    
    int main(void)
    {
        int a;
        char *b;
        
        dataUnion c;
    
        c.intData = 0;
        c.charData = "foobar";
    
        funcArray[0] = (void (*)(dataUnion))func1;
        funcArray[1] = (void (*)(dataUnion))func2;
    
        a = ((int (*)(dataUnion))(funcArray[0]))(c);
        b = ((char *(*)(dataUnion))(funcArray[1]))(c);
    
        printf("%d\n", a);
        printf("%s\n", b);
    
        return 0;
    }
    P.S.: If you expected the first printf() to print 0, it doesn't...
    Last edited by Bachstelze; August 15th, 2012 at 04:12 AM.
    「明後日の夕方には帰ってるからね。」


  3. #3
    Join Date
    Nov 2009
    Beans
    41

    Re: Type casting a void function pointer in C

    That works, thanks!

    But the output shows:

    4195972
    foobar

    instead of:

    0
    foobar

    I tried assigning a directly to c.intData, but that still returns the same thing.

    By learning the ropes, I meant I haven't done anything substantial beyond a few hundred lines of code, and I still haven't gone beyond the basics. I guess I misunderstood the phrase

  4. #4
    Join Date
    Nov 2009
    Beans
    41

    Re: Type casting a void function pointer in C

    Alright, I changed it to a struct. Thanks a lot!

  5. #5
    Join Date
    Nov 2005
    Location
    Bordeaux, France
    Beans
    11,294
    Distro
    Ubuntu 12.04 Precise Pangolin

    Re: Type casting a void function pointer in C

    Learn about what a union is, and how it is different from a struct. For that matter, also learn about what an array is, because your code says that you are not very clear on that, either.
    「明後日の夕方には帰ってるからね。」


  6. #6

    Re: Type casting a void function pointer in C

    "function-returning-pointer-to-char" isn't compatible with "function-returning-int" or "function-returning-void". You can't cast them and pass them about interchangeably or treat one as if it were another, because knowing the return value of a function is essential to calling it.

    If you were dealing with non-function types, then you could store a pointer-to-A and a pointer-to-B both as void * and cast it to (A *) or (B *) respectively when you dereference it. But that's not guaranteed to be possible with function types (C doesn't assume a von Neumann architecture, so pointers to code aren't necessarily interchangeable with pointers to data).

    What you might do is write your interchangeable functions to return a pointer-to-void; that way they all have the same return type and you can represent the function pointers interchangeably as `void (*)(dataUnion)`.

    Code:
    /* returns 1, then 2, then 3, etc. up until 100 */
    void *f1(void) { static int i = 0; if (i < 100) i++; return &i; }
    /* returns 'A', then 'B', etc. up until 'Z' */
    void *f2(void) { static char c = 'A'; if (c < 'Z') c++; return &c; }
    
    void (*a[2])(void) = { f1, f2 };
    However, you'll also need to keep track of what type each pointer actually returns a pointer to, so that you can cast it correctly when you call it:

    Code:
    void *p = a[0](); /* p contains a pointer to int */
    void *q = a[1](); /* q contains a pointer to char */
    
    char ch1 = *( (char *) p); /* WRONG -- converts p to pointer-to-char */
    char ch2 = *( (char *) q); /* ok */
    
    int  i1  = *( (int  *) q); /* WRONG -- converts q to pointer-to-int */
    int  i1  = *( (int  *) p); /* ok */
    This means you need a way to determine, at runtime, which pointers point to functions returning which types. You might do this by maintaining another parallel array that simply tracks the appropriate type.

    I'm sure most of this isn't making much sense. I'll conclude with one other observation: this

    Code:
        funcArray[0] = malloc(sizeof(int));
        funcArray[0] = (int (*)(dataUnion)) funcArray[0];
        funcArray[0] = &func1;
    is two no-ops followed by a mistake. I've already addressed why the last is a mistake, but the first two are no-ops because they're all assignment statements that assign to the same object. In other words, the first one is overwritten by the second, which is overwritten by the third. If you want conversions to happen when assigning func1 to funcArray[0], you have to do it all in one step.

    Also I don't approve of your use of typedef.

  7. #7

    Re: Type casting a void function pointer in C

    Thought I'd just add, Bachstelze's version does work, but it depends on... I think undefined behavior when casting a function pointer to a pointer to a function returning a different type. Function pointers of different types may have different alignment requirements and conversions between them are not described by the Standard. I think.

  8. #8
    Join Date
    Nov 2005
    Location
    Bordeaux, France
    Beans
    11,294
    Distro
    Ubuntu 12.04 Precise Pangolin

    Re: Type casting a void function pointer in C

    Quote Originally Posted by trent.josephsen View Post
    "function-returning-pointer-to-char" isn't compatible with "function-returning-int" or "function-returning-void". You can't cast them and pass them about interchangeably or treat one as if it were another, because knowing the return value of a function is essential to calling it.
    You can, however, cast a function-returning-int to a function-returning-void and then back, and it will be equal to the original pointer. This is what OP does here (or at least what I do in my solution).

    EDIT: 6.3.2.3, §8 (in C99).
    Last edited by Bachstelze; August 15th, 2012 at 04:26 AM.
    「明後日の夕方には帰ってるからね。」


  9. #9
    Join Date
    Nov 2005
    Location
    Bordeaux, France
    Beans
    11,294
    Distro
    Ubuntu 12.04 Precise Pangolin

    Re: Type casting a void function pointer in C

    I should add that this is not a panacea, and you should be very careful if you do this. In particular, you need to carefully keep track of which type each pointer was originally in order to convert it back to the correct type. If you don't, you enter undefined behavior, and the compiler will not warn you!

    For example if I swap the indices on lines 32 and 33:

    Code:
    firas@aoba ~ % cat test.c                                            
    #include <stdio.h>
    #include <malloc.h>
    
    struct data {
        int intData;
        char *charData;
    };
    
    void (*funcArray[2])(struct data);
    
    int func1(struct data param) {
        return param.intData;
    }
    
    char *func2(struct data param) {
        return param.charData;
    }
    
    int main(void)
    {
        int a;
        char *b;
        
        struct data c;
    
        c.intData = 0;
        c.charData = "foobar";
    
        funcArray[0] = (void (*)(struct data))func1;
        funcArray[1] = (void (*)(struct data))func2;
    
        /* Indices swapped below! */
        a = ((int (*)(struct data))(funcArray[1]))(c);
        b = ((char *(*)(struct data))(funcArray[0]))(c);
    
        printf("%d\n", a);
        printf("%s\n", b);
    
        return 0;
    }
    firas@aoba ~ % gcc -std=c99 -pedantic -Wall -Wextra -g -o test test.c
    firas@aoba ~ % ./test 
    4196076
    zsh: segmentation fault (core dumped)  ./test
    Last edited by Bachstelze; August 15th, 2012 at 05:20 AM.
    「明後日の夕方には帰ってるからね。」


  10. #10
    Join Date
    Nov 2009
    Beans
    41

    Re: Type casting a void function pointer in C

    I got the general idea of how to deal with function pointers, from the above posts. Thanks guys!

    One more question, though, I want to create a dynamic array containing function pointers, so that depending on the number of functions, I can realloc the array. Is this possible, as creating an array of pointers to data?

    I did something like this:

    Code:
    #include <stdio.h>
    #include <malloc.h>
    
    struct dataStruct {
        int intData;
        char *charData;
    };
    
    void *(*funcArray)(struct dataStruct param);
    
    int func1(struct dataStruct param) {
        return param.intData;
    }
    
    char *func2(struct dataStruct param) {
        return param.charData;
    }
    
    int main(void)
    {
        int a;
        char *b;
     
        struct dataStruct c;
            
        c.intData = 0;
        c.charData = "foobar";
    
        printf("%d\n", sizeof(void *(*)(struct dataStruct)));
    
        funcArray = malloc(2 * sizeof(void *(*)(struct dataStruct)));
    
        funcArray[0] = (void (*)(struct dataStruct))func1;
        funcArray[1] = (void (*)(struct dataStruct))func2;
    
        a = ((int (*)(struct dataStruct))(*(*funcArray)))(c);
        b = ((char *(*)(struct dataStruct))(*(*funcArray + 1)))(c);
    
        printf("%d\n", a);
        printf("%s\n", b);
    
        return 0;
    }
    But that returns an error:

    ./e executors.c: In function ‘main’:
    executors.c:33:14: error: subscripted value is pointer to function
    executors.c:34:14: error: subscripted value is pointer to function

    Does this have something to do with C not assuming a Von Neumann architecture?

Page 1 of 2 12 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •