Thread: Pointer to Function

  1. #1
    Registered User Vespasian's Avatar
    Join Date
    Aug 2011
    Posts
    181

    Pointer to Function

    Hi all. Firstly, im new here and I hope during my stay I will help many people an in turn receive help from others. Ive been studying C programming for over a year now and have been reading through the K&R bible.

    Anyway enough of that...

    What I cant seem to understand is one of their examples. I wont post entire code but rather point out the essentials. Two functions are declared that both have the same data type arguments and same return type:

    Code:
    int numcmp(char *, char *);
    Code:
    int strcmp(char *s, char *t)
    Thus, we can use a function pointer to point to either one of them. (Because one of the main requirements of function pointers is that they point to the same function type in both return and arguments.

    Next, a function called qsort is used. It takes four arguments. Ignore the first three and focus on the fourth. It says that it takes in a function pointer whos local name is "comp". Its a function pointer because the name and * in front of it are together parenthesized. Further, this function pointer is one that points to a function that returns an int and expects two void arguments:

    Code:
    void qsort(void *lineptr[], int left, int right,
    int (*comp)(void *, void *));
    Now when this function want to be called, its coded as:

    Code:
    qsort((void**) lineptr, 0, nlines-1,
    (int (*)(void*,void*))(numeric ? numcmp : strcmp));
    Now my problem is ultimately the fourth parameter. I simply do not get it. I understand the
    Code:
    (numeric ? numcmp : strcmp)
    part. It chooses which function to call numcmp or strcmp based on a variable called numeric. But its what is infront of it that I cannot understand and the entire internet has not given me an answer:
    Code:
    (int (*)(void*,void*))
    Is that some sort of cast? Why does it even need to be cast?

    Why void arguments? It doesnt match the the char arguments
    Why the (*)? I dont even know where to begin

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Frankly, I think that's an ugly example, and I rarely, if ever, see function pointer casts in code.

    Quote Originally Posted by Vespasian View Post
    Is that some sort of cast? Why does it even need to be cast?
    Yes, it's a cast. You need it because if you look at the comp function in qsort, it returns an int, but takes two pointers to void (not two pointers to char like strcmp and numcmp). Casts are often a way to shut up the compiler when it warns you about type mismatch. That means you think you're smarter than the compiler, which is probably not true.

    Why void arguments? It doesnt match the the char arguments
    The void * arguments are there because you don't want to restrict what qsort can take. Any pointer can be converted to a void pointer (EDIT: automatically by the compiler), and you can cast it back to the type you need in the comparison function. If you had char * instead of void *, every function would have to take char * (like numcmp does), and you would have to explicitly cast the params every time you call it, even outside the context of qsort.

    Why the (*)? I dont even know where to begin
    Just like when you cast something to int, you don't need to put a variable name in the cast part:
    Code:
    int foo = (int) bar;  // notice no name inside the casting parentheses
    with a function pointer cast, you don't need to give a name to the function pointer. You're only describing the type of the thing, which in this case is pointer to function taking two void * arguments and returning an int.
    Code:
    int (*)(void *, void *)
    As a note, when I do this sort of stuff, I create my own functions that take void pointers and do a cast inside to the right type:
    Code:
    int string_compare(void *a, void *b)
    {
        return strcmp((char *) a, (char *) b);
    }
    
    int num_compare(void *a, void *b)
    {
        return *((int *) a) - *((int *) b);
    }
    ...
    qsort(a, b, c, string_compare);
    qsort(a, b, c, num_compare);
    It may cost a slight performance hit, but it removes any ugly/difficult function pointer casts, and I generally put code readability over execution speed.
    Last edited by anduril462; 08-16-2011 at 12:21 PM.

  3. #3
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    In other words: take out the word "comp" in your example, and that's the type (just like if you take out the word "lineptr" and you get the type void *[]).

    The usual method as I understand it is to write your function properly in the first place, i.e., as taking void* arguments.

  4. #4
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Vespasian View Post
    What I cant seem to understand is one of their examples. I wont post entire code but rather point out the essentials. Two functions are declared that both have the same data type arguments and same return type:

    Code:
    int numcmp(char *, char *);
    Code:
    int strcmp(char *s, char *t)
    Thus, we can use a function pointer to point to either one of them.
    No you can't. Look closely... one is a function declaration the other is a function definition... You can point to the second one, but not the first.
    (For a more detailed explaination check out "Declaration" and "Definition" in your beloved K&R)

  5. #5
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Actually, yes you can.......

    Quote Originally Posted by C99
    6.7.5.3.6 A parameter type list specifies the types of, and may declare identifiers for, the parameters of the function.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  6. #6
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by AndrewHunter View Post
    Actually, yes you can.......
    Not *as written*....

    Also it didn't work when I tried it.

  7. #7
    Registered User Vespasian's Avatar
    Join Date
    Aug 2011
    Posts
    181
    Thanks anduril, your explanation makes sense. But I still have questions regarding this whole "cast" business.

    Quote Originally Posted by CommonTater View Post
    Not *as written*....

    Also it didn't work when I tried it.
    Anyway, that was actually a typo ;-P I left out the s and the t in numcmp.

  8. #8
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Quote Originally Posted by Vespasian View Post
    Thanks anduril, your explanation makes sense. But I still have questions regarding this whole "cast" business.
    What specifically don't you understand? qsort is suppose to be a generalized function, hence it deals with void* relying on the user to appropriately cast the values when it is time to use them.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  9. #9
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by Vespasian View Post
    Now when this function want to be called, its coded as:

    Code:
    qsort((void**) lineptr, 0, nlines-1,
    (int (*)(void*,void*))(numeric ? numcmp : strcmp));
    Is that some sort of cast? Why does it even need to be cast?
    You said you understood the bit with the fake if operator "?:" (that's not what it's called but I forget right now). Anyway, that results in a function pointer being passed to qsort as an argument; when you pass the name of a function to another function, a pointer to function type is generated. We cast the pointer to another type (EWW EWW EWW) because we want the argument to match the type of function pointer qsort uses.

  10. #10
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by whiteflags View Post
    You said you understood the bit with the fake if operator "?:" (that's not what it's called but I forget right now).
    Ternaray.

  11. #11
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by CommonTater View Post
    Not *as written*....

    Also it didn't work when I tried it.
    Yes, as written. Does this not work for you?
    Code:
    int numcmp(char *, char *);
    
    int main(void) {
        int (*comp)(char *, char *) = numcmp;
        return 0;
    }
    
    int numcmp (char *s, char *t) {
        return 5; /*Not important for this*/
    }

  12. #12
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by tabstop View Post
    Yes, as written. Does this not work for you?
    Code:
    int numcmp(char *, char *);
    
    int main(void) {
        int (*comp)(char *, char *) = numcmp;
        return 0;
    }
    
    int numcmp (char *s, char *t) {
        return 5; /*Not important for this*/
    }
    His original example has two different names there... the second one worked, the first one did not... because it was pointing at a prototype with no function present. As in, you can't point at a prototype... you need the actual function.

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by CommonTater View Post
    His original example has two different names there... the second one worked, the first one did not... because it was pointing at a prototype with no function present. As in, you can't point at a prototype... you need the actual function.
    His original example has two different names there because they were two different functions. One for comparing numeric data, one for comparing string data.

  14. #14
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by tabstop View Post
    His original example has two different names there because they were two different functions. One for comparing numeric data, one for comparing string data.
    Please go back and look again... Better still...
    Quote Originally Posted by first post
    int numcmp(char *, char *);
    int strcmp(char *s, char *t)
    See that trailing semicolon? THAT is what I was talking about...

  15. #15
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    The official errata page for K&R does note that this example "is not only complicated, but only barely passes muster." It doesn't really pass muster if you're being really pedantic about it, as the errata page hints at ("the example will almost certainly work in practice").

    This particular example would only fail on a particularly perverse implementation, but even so, there's no particular reason to do it this way. As has been stated, create a function with the proper prototype, and you don't have to cast at all, plus you have the benefit of knowing your code is valid on all implementations, perverse or otherwise.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. passing method pointer as a function pointer
    By sevcsik in forum C++ Programming
    Replies: 5
    Last Post: 12-30-2007, 06:19 AM
  2. Replies: 7
    Last Post: 07-04-2007, 12:46 PM
  3. Replies: 9
    Last Post: 01-02-2007, 04:22 PM
  4. Replies: 4
    Last Post: 11-05-2006, 02:57 PM
  5. Replies: 6
    Last Post: 11-29-2004, 08:50 AM