#1
  1. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12

    function pointer stuff


    this function call line is confusing me a bit:
    Code:
    qsorty((void **) lineptr, 0, nlines-1, (int (*)(void *, void *))(fold ? strcmpulc : strcmp));
    i don't understand what the (void **) part is. it doesn't match up with the qsorty decleration which is:
    Code:
    void qsorty(void *lineptr[], int left, int right, int (*comp)(void *, void *));
    also the (int (*)(void *, void *))(fold ? strcmpulc : strcmp) part from the function call i kind of understand. it seems that it's working a bit like the %d's in a printf statement - the place holder is getting replaced. so (*) is getting replaced by the answer to fold ? which is going to be one of the two pointers to functions.

    what is that makes it behave like that? is that something to do with the (void **) maybe? (i'm guessing)

    also, say you've got a situation where there isn't any option about which function pointer should be passed (like in the (fold ? strcmpulc : strcmp) part), is this the only way to say that? :
    Code:
    qsorty((void **) lineptr, 0, nlines-1, (int (*)(void *, void *))(numcmp));
    that works but it seems like it should be possible to use something like:
    Code:
    qsorty((void **) lineptr, 0, nlines-1, (int (*numcmp)(void *, void *)));
    or
    Code:
    qsorty((void **) lineptr, 0, nlines-1, (*numcmp)(void *, void *));
    but they aren't ok.
  2. #2
  3. *bounce*
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2002
    Location
    Delft, The Netherlands
    Posts
    514
    Rep Power
    42
    i don't understand what the (void **) part is. it doesn't match up with the qsorty declaration...
    Bear in mind that in a function declaration (and only in a function declaration!) pointer-to-type and array-of-type are identical; they're synonymous, and the only reason why you might want to choose array-of-type (type[]) over pointer-to-type (type*) is as a hint to the programmer that it doesn't point to a single element of type, but to the first in a sequence of type.

    In the function call I assume that lineptr is an array of pointer-to-char, which is why the typecast to (void **) makes sense, being that in a function declaration, **void is identical to *void[] as I just explained.

    also the (int (*)(void *, void *))(fold ? strcmpulc : strcmp) part from the function call i kind of understand. it seems that it's working a bit like the %d's in a printf statement - the place holder is getting replaced. so (*) is getting replaced by the answer to fold ? which is going to be one of the two pointers to functions.
    Let's break that up into two pieces, the first part being a typecast, and the second being the conditional operator:

    The (fold ? strcmpulc : strcmp) bit is fairly straight-forward; it's the conditional operator ?: (check A7.16 on page 208 of K&R if you're unfamiliar with it).

    Basically that expression evaluates to either strcmpulc or strcmp, depending on the value of fold. So what you get, is a function pointer.

    The problem is that qsorty expects a pointer to a function that has a prototype of
    Code:
    int (*cmp)(void *, void *)
    , but strcmp and strcmpulc are (probably) declared as
    Code:
    int (*cmp)(const char *, const char *)
    That's what the typecast is for. It might look draconian, but yes, it really is a typecast. :) It casts the pointer-to-function-with-two-pointer-to-char-arguments-and-returning-an-int
    to a pointer-to-function-with-two-pointer-to-void-arguments-and-returning-an-int.

    Code:
    int (*)(void *, void *)
    can be broken down as follows:

    Code:
    int              /* returning an int */
    (*)              /* pointer-to */
    (void *, void *) /* function with two pointer-to-void arguments */
    It needs the parentheses around the asterisk (the pointer-to bit) to make sure it isn't associated with the return type, int.

    I hope this clears things up a bit. Keep asking though; it keeps us on our toes :D
    "A poor programmer is he who blames his tools."
    http://analyser.oli.tudelft.nl/
  4. #3
  5. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    thanks for your reply.
    , but strcmp and strcmpulc are (probably) declared as
    Code:
    int (*cmp)(const char *, const char *)
    they're just declared normally :
    Code:
    int strcmpulc(char *, char *);
    and the other is part of string.h so it's also declared in the usual way. maybe that's why i get :

    warning: pointer type mismatch in conditional expression

    for that line? :) probably is. but then saying that, on this function call line:
    Code:
    qsorty((void **) lineptr, 0, nlines-1, (int (*)(void *, void *))(numcmp));
    i don't get that warning and numcmp is declared like so:
    Code:
    int numcmp(char *, char *);



    (int (*)(void *, void *))(fold ? strcmpulc : strcmp)

    two pieces, the first part being a typecast, and the second being the conditional operator
    i understand that apart from why, when there's no conditional aspect - only one possible function to call, can i not say:
    Code:
    (int (*strcmp)(void *, void *))
    or something similar? does it have to be in two pieces even when no conitional element? (in the call to the function that is)

    I hope this clears things up a bit.
    a bit, yes thanks :) i need to go over it a bit more to let it sink in
    Last edited by balance; April 9th, 2003 at 08:57 AM.
  6. #4
  7. *bounce*
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2002
    Location
    Delft, The Netherlands
    Posts
    514
    Rep Power
    42
    they're just declared normally
    Well, my emphasis wasn't on the consts, but the fact that it's char* instead of void*.

    I understand that apart from why, when there's no conditional aspect - only one possible function to call, can i not say:

    Code:
    (int (*strcmp)(void *, void *))
    or something similar? does it have to be in two pieces even when no conitional element?
    The code snippet above is just a semi-colon short of a declaration statement. It would declare strcmp as being a pointer-to-function. What the qsorty function call contains though, is a type cast, which has a general form of

    Code:
    (type-to-cast-to) (expression-to-cast)
    Just like you can cast a real expression to an integer expression by saying (int)(3.14159), you can cast pointer-to-function expressions.

    The thing is that not all function pointers are alike; some pointers point to a function that takes an int as an argument, others point to a function that returns a double, etc, etc. They're all different, because the functions' declarations are different.

    Hence, when you've defined a function (qsorty in this case) that expects as its third parameter a pointer to a function that takes two pointer-to-void arguments, and you call it with its third argument being a pointer to a function that takes two pointer-to-char arguments (strcmp, for example), then you'll get a warning (if not error) saying that the types don't match. That's why you have to perform a type cast.

    i don't get that warning and numcmp is declared like so
    Again, that would be due to the type cast :)
    "A poor programmer is he who blames his tools."
    http://analyser.oli.tudelft.nl/
  8. #5
  9. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    ok i think i've got it. thanks-a-lot for your explenation analyser :)
  10. #6
  11. *bounce*
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2002
    Location
    Delft, The Netherlands
    Posts
    514
    Rep Power
    42
    You're quite welcome :)
    "A poor programmer is he who blames his tools."
    http://analyser.oli.tudelft.nl/

IMN logo majestic logo threadwatch logo seochat tools logo