*generic* pointer to function(s)?

Discussion in 'C Programming' started by juerg.lemke@yahoo.com, Dec 3, 2007.

  1. Guest

    Hi everyone

    I am interested in having multiple functions with different prototypes
    and deciding, by setting a pointer, which of them to use later in the
    program.

    Eg:

    int f1(void);
    char* f2(int);
    /* ... many more of these to choose from */

    /* ? correct declaration of generic_ptr ? */

    if (/*...*/)
    generic_ptr = f1;
    else
    generic_ptr = f2;

    generic_ptr(/* using correct args */)

    How should I define generic_ptr? Is (void*) ok? It seems to work on my
    machine, but I would like to know if this is standard/portable.

    Thank you for any help

    Juergen
    , Dec 3, 2007
    #1
    1. Advertising

  2. wrote:
    > Hi everyone
    >
    > I am interested in having multiple functions with different
    > prototypes and deciding, by setting a pointer, which of
    > them to use later in the program.
    >
    > Eg:
    >
    > int f1(void);
    > char* f2(int);
    > /* ... many more of these to choose from */
    >
    > /* ? correct declaration of generic_ptr ? */
    >
    > if (/*...*/)
    > generic_ptr = f1;
    > else
    > generic_ptr = f2;
    >
    > generic_ptr(/* using correct args */)
    >
    > How should I define generic_ptr?


    You can't.

    > Is (void*) ok?


    No.

    > It seems to work on my machine,


    You got unlucky.

    > but I would like to know if this is standard/portable.


    It isn't. The most common generic function pointer type
    is void (*)(), though that won't cater for variadic
    functions. Moreover, you generally need to cast to
    and from the original function pointer in order to use
    it.

    To avoid the casting, it's much more common to make all
    your functions have the same prototype. Another
    alternative is to use a union type.

    --
    Peter
    Peter Nilsson, Dec 3, 2007
    #2
    1. Advertising

  3. Eric Sosman Guest

    wrote:
    > Hi everyone
    >
    > I am interested in having multiple functions with different prototypes
    > and deciding, by setting a pointer, which of them to use later in the
    > program.
    >
    > Eg:
    >
    > int f1(void);
    > char* f2(int);
    > /* ... many more of these to choose from */
    >
    > /* ? correct declaration of generic_ptr ? */
    >
    > if (/*...*/)
    > generic_ptr = f1;
    > else
    > generic_ptr = f2;


    This is not possible, but you can do something like

    void (*generic_ptr)();
    if (/*...*/)
    generic_ptr = (void(*)()) f1;
    else
    generic_ptr = (void(*)()) f2;

    Although I usually consider typedefs for pointer types to be
    a Bad Thing, this is one of the exceptions where it seems to
    me the readability can be improved a lot:

    typedef void (*FuncPtr)();
    FuncPtr generic_ptr;
    if (/*...*/)
    generic_ptr = (FuncPtr)f1;
    else
    generic_ptr = (FuncPtr)f2;

    > generic_ptr(/* using correct args */)


    You can *almost* do this, but only if all of your functions
    obey some rather strange restrictions:

    - All of f1, f2, ... and generic_ptr must return the same
    type, or all must be void

    AND

    - None of f1, f2, ... and generic_ptr can be a variadic
    function, or all must be variadic and have the same number
    and types of fixed arguments

    AND

    - If the argument types are omitted (as above), then all the
    arguments to all of f1, f2, ... must be non-promotable, or
    all of f1, f2, ... must be defined with the obsolescent
    "K&R" syntax.

    The problem is that the type of the pointer with which you
    call a function must agree with the actual type of the function
    that is called. The strange restrictions listed above allow you
    to skirt the agreement rule just a little bit -- but there's
    still no way you can use the same pointer expression to call a
    function returning int *and* a function returning double, for
    example.

    An alternative is to cast at the point of call, which again
    is clarified by the use of some typedefs:

    typedef int (*IntOfVoid)(void);
    typedef char* (*StrOfInt)(int);
    if (/*...*/)
    i = ((IntOfVoid)generic_ptr)();
    else
    s = ((StrOfInt)generic_ptr)(42);

    > How should I define generic_ptr? Is (void*) ok? It seems to work on my
    > machine, but I would like to know if this is standard/portable.


    See above. No. Happenstance, and it's not.

    If the functions f1, f2, ... really bear no resemblance to
    each other you're pretty much doomed to casting -- but in such a
    case it's hard to see why you'd want to use a single "generic"
    pointer in the first place. If they are related in some way but
    differ in details, it may be better to use wrapper functions.
    For example, suppose all the functions return int values, all
    take two int arguments, and some also take a third string argument.
    You could do something like

    int f1(int, int, char*);
    int f2(int, int, char*);
    int f3(int, int); /* only two arguments */

    int wrapf3(int x, int y, char* unused) {
    return f3(x, y);
    }

    typedef int (*FuncPtr)(int, int, char*);
    FuncPtr fptr;

    if (/*...*/)
    fptr = f1;
    else if (/*...*/)
    fptr = f2;
    else
    fptr = wrapf3; /* note indirection */

    printf ("%d\n", fptr(42, 29, "Zaphod Rulez!"));

    This technique may appear limiting at first glance, but when
    you start applying it to actual "families" of "broadly similar"
    functions it works quite well.

    --
    Eric Sosman, Dec 3, 2007
    #3
  4. Guest

    Eric, Peter

    Thank you for the stupendously informative replies.

    J
    , Dec 3, 2007
    #4
  5. writes:
    > I am interested in having multiple functions with different prototypes
    > and deciding, by setting a pointer, which of them to use later in the
    > program.
    >
    > Eg:
    >
    > int f1(void);
    > char* f2(int);
    > /* ... many more of these to choose from */
    >
    > /* ? correct declaration of generic_ptr ? */
    >
    > if (/*...*/)
    > generic_ptr = f1;
    > else
    > generic_ptr = f2;
    >
    > generic_ptr(/* using correct args */)
    >
    > How should I define generic_ptr? Is (void*) ok? It seems to work on my
    > machine, but I would like to know if this is standard/portable.


    void* is a generic object pointer type, in the sense that (1) you can
    convert any object pointer to void* and back again, and get the
    original pointer, and (2) such conversions can be done implicitly
    (e.g., by a simple assignment rather than a cast).

    There's no guarantee that converting a function pointer to or from
    void* will give you anything meaningful. There is no generic function
    pointer type in the sense of (2) above; conversions to and from
    function pointer types must be explicit. But in the sense of (1),
    *all* function pointer types are effectively generic; you can convert
    a function pointer to any other function pointer type and back again
    and get the same pointer. In effect, all function pointers "smell
    alike", something that's not the case for object pointers.

    But calling a function via a pointer of the wrong type invokes
    undefined behavior.

    Your best bet is probably to use something like ``void(*)(void)'',
    (use a typedef) but you'll need to explicitly convert to or from this
    type. Since there's no runtime representation of types (e.g., you
    can't say ``if (typeof(x) == int)''), you'll need to use a switch
    statement to select the proper type, and write each type of call
    individually.

    --
    Keith Thompson (The_Other_Keith) <>
    Looking for software development work in the San Diego area.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Dec 4, 2007
    #5
  6. CBFalconer Guest

    Peter Nilsson wrote:
    >

    .... snip ...
    >
    > It isn't. The most common generic function pointer type is
    > void (*)(), though that won't cater for variadic functions.
    > Moreover, you generally need to cast to and from the original
    > function pointer in order to use it.


    I believe the standard bans casts to and from function pointers.

    --
    Chuck F (cbfalconer at maineline dot net)
    <http://cbfalconer.home.att.net>
    Try the download section.



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Dec 4, 2007
    #6
  7. In article <>,
    CBFalconer <> wrote:
    >Peter Nilsson wrote:
    >>

    >... snip ...
    >>
    >> It isn't. The most common generic function pointer type is
    >> void (*)(), though that won't cater for variadic functions.
    >> Moreover, you generally need to cast to and from the original
    >> function pointer in order to use it.


    >I believe the standard bans casts to and from function pointers.


    Casting between different function pointer types is explicitly
    permitted; using the result is left undefined unless it matches
    the actual call.

    If I recall correctly, casting between a function pointer and an
    object pointer (or the other way) is not banned, and that C
    implementations are permitted to assign semantics to the result,
    but the semantics are not specified in the C standards.

    It -is- the case that the description of the semantics of
    casting pointers takes care to group object pointers seperately from
    function pointers. It is one of those clauses that is easy to
    mis-read, in the sense that one's expectation (from experience)
    that object pointers and function pointers "are" (as far as
    one has ever encountered) convertable, can easily lead one to
    overlook the seperation and "read in" a convertability that is
    not present in the clause. If I had written the relevant paragraph,
    I would probably have pointed out the non-covertability rather than
    leaving it implied by simply leaving "object types" out of the list.
    But then if I -had- written the standard, it probably would have been
    four or five times as long as it turned out to be, as conciseness
    never has been one of my strong points.
    --
    "Any sufficiently advanced bug is indistinguishable from a feature."
    -- Rich Kulawiec
    Walter Roberson, Dec 4, 2007
    #7
  8. pete Guest

    Walter Roberson wrote:

    > If I recall correctly, casting between a function pointer and an
    > object pointer (or the other way) is not banned, and that C
    > implementations are permitted to assign semantics to the result,
    > but the semantics are not specified in the C standards.


    That's what "undefined" means.

    Implementations are permitted to assign semantics
    to the result of (1 / 0) also.

    --
    pete
    pete, Dec 4, 2007
    #8
  9. pete <> writes:
    > Walter Roberson wrote:
    >> If I recall correctly, casting between a function pointer and an
    >> object pointer (or the other way) is not banned, and that C
    >> implementations are permitted to assign semantics to the result,
    >> but the semantics are not specified in the C standards.

    >
    > That's what "undefined" means.


    Yes, but the previous poster had speculated that such casts are
    "banned". They aren't.

    > Implementations are permitted to assign semantics
    > to the result of (1 / 0) also.


    True.

    --
    Keith Thompson (The_Other_Keith) <>
    Looking for software development work in the San Diego area.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Dec 4, 2007
    #9
  10. Guest

    CBFalconer wrote:
    > Peter Nilsson wrote:
    > >

    > ... snip ...
    > >
    > > It isn't. The most common generic function pointer type is
    > > void (*)(), though that won't cater for variadic functions.
    > > Moreover, you generally need to cast to and from the original
    > > function pointer in order to use it.

    >
    > I believe the standard bans casts to and from function pointers.


    You believe incorrectly. Section 6.3.2.3p8:
    " A pointer to a function of one type may be converted to a pointer to
    a function of another
    type and back again; the result shall compare equal to the original
    pointer."
    , Dec 4, 2007
    #10
  11. <> wrote in message
    > I am interested in having multiple functions with different prototypes
    > and deciding, by setting a pointer, which of them to use later in the
    > program.
    >
    > Eg:
    >
    > int f1(void);
    > char* f2(int);
    > /* ... many more of these to choose from */
    >

    Don't go down this route.
    Building an argument list at runtime is one of the very few operations that
    C will not allow you to do.
    You can cast to and from void (*fptr)(void) s and any other type on almost
    every architecture, but that avails you little if you are then going to
    hardcode the calls. You might as well do the job properly and use a union.

    --
    Free games and programming goodies.
    http://www.personal.leeds.ac.uk/~bgy1mm
    Malcolm McLean, Dec 4, 2007
    #11
  12. Flash Gordon Guest

    Malcolm McLean wrote, On 04/12/07 22:06:
    > <> wrote in message
    >> I am interested in having multiple functions with different prototypes
    >> and deciding, by setting a pointer, which of them to use later in the
    >> program.
    >>
    >> Eg:
    >>
    >> int f1(void);
    >> char* f2(int);
    >> /* ... many more of these to choose from */
    >>

    > Don't go down this route.
    > Building an argument list at runtime is one of the very few operations
    > that C will not allow you to do.


    True.

    > You can cast to and from void (*fptr)(void) s and any other type on
    > almost every architecture,


    You can do it on *every* architecture that has a C compiler because the
    C standard says you can do it.

    > but that avails you little if you are then
    > going to hardcode the calls. You might as well do the job properly and
    > use a union.


    Whether a union buys you anything will depend on the exact situation.
    --
    Flash Gordon
    Flash Gordon, Dec 4, 2007
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Murat Tasan
    Replies:
    1
    Views:
    8,030
    Chaitanya
    Feb 3, 2009
  2. glen stark
    Replies:
    2
    Views:
    690
    Ron Natalie
    Oct 10, 2003
  3. Replies:
    2
    Views:
    426
  4. minlearn
    Replies:
    2
    Views:
    445
    red floyd
    Mar 13, 2009
  5. Replies:
    2
    Views:
    790
Loading...

Share This Page