simplifying c code with function pointers

Discussion in 'C Programming' started by goldfita@signalsguru.net, May 11, 2006.

  1. Guest

    I love this place. This one problem keeps coming back to bite me.
    Suppose I have the following situation (actually I do).

    func1()
    {
    codeA
    somefunc1()
    codeB
    }

    func2()
    {
    codeA
    somefunc2()
    codeB
    }

    func3()
    {
    codeA
    somefunc3()
    codeB
    }

    I'm trying to follow the DRY school of thought and simplify this down
    to one function. Sometimes I just use macros, but it's just awful.
    Then I got to thinking, gee if only c had closures. Well I did some
    searching, and according to wikipedia, you can simulate closures with
    just a function pointer that takes a void pointer. The trouble is
    those inner functions don't always take the same number of parameters.
    I could make arbitrary structures to contain all the parameters into he
    void pointer, but in my opinion, making single use structures to lump
    arbitrary data together is worse than the macro method.

    So, next I tried this.

    #include <stdio.h>

    void foo1(int a)
    {
    printf("%d \n",a);
    }

    void foo2(int a, int b)
    {
    printf("%d %d\n",a,b);
    }

    void do_foo(void (*foo)(), int opt)
    {
    if(opt == 1)
    foo(5);
    else if(opt == 2)
    foo(5,10);
    }

    int main(void)
    {
    do_foo(&foo1,1);
    do_foo(&foo2,2);
    return 0;
    }

    I'm using opt to choose the function definition. It's a bit ugly, but
    I'm ok with it. I'm just not sure if it's legal. I see lots of "don't
    ever do this" when I google for unspecified function arguments.

    So anyway, c gurus, what is the smart way to handle this? And what do
    you think about closures in C, um, 2009 (just kidding)?
     
    , May 11, 2006
    #1
    1. Advertising

  2. pemo Guest

    wrote:

    <snip>

    >
    > #include <stdio.h>
    >
    > void foo1(int a)
    > {
    > printf("%d \n",a);
    > }
    >
    > void foo2(int a, int b)
    > {
    > printf("%d %d\n",a,b);
    > }
    >
    > void do_foo(void (*foo)(), int opt)
    > {
    > if(opt == 1)
    > foo(5);
    > else if(opt == 2)
    > foo(5,10);
    > }
    >
    > int main(void)
    > {
    > do_foo(&foo1,1);
    > do_foo(&foo2,2);
    > return 0;
    > }
    >


    <snip>

    > do_foo(&foo1,1);
    > do_foo(&foo2,2);


    &foo1 etc have the type pointer to pointer to function [...], so you should
    remove the &.



    --
    ==============
    Not a pedant
    ==============
     
    pemo, May 11, 2006
    #2
    1. Advertising

  3. pemo said:

    > wrote:

    <snip>
    >> do_foo(&foo1,1);
    >> do_foo(&foo2,2);

    >
    > &foo1 etc have the type pointer to pointer to function [...], so you
    > should remove the &.


    I agree that the & is ugly and unnecessary, but you're wrong about the type.

    The function pointer foo1 can be expressed as &foo1 too; they are both
    "pointer to function". It's a bug-ugly wart, but it's true.


    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, May 11, 2006
    #3
  4. pemo Guest

    Richard Heathfield wrote:
    > pemo said:
    >
    >> wrote:

    > <snip>
    >>> do_foo(&foo1,1);
    >>> do_foo(&foo2,2);

    >>
    >> &foo1 etc have the type pointer to pointer to function [...], so you
    >> should remove the &.

    >
    > I agree that the & is ugly and unnecessary, but you're wrong about
    > the type.
    >
    > The function pointer foo1 can be expressed as &foo1 too; they are both
    > "pointer to function". It's a bug-ugly wart, but it's true.


    Thanks for the correction Richard - very interesting! Don't suppose you
    have a handy ref into the standard?

    --
    ==============
    Not a pedant
    ==============
     
    pemo, May 11, 2006
    #4
  5. pemo said:

    > Richard Heathfield wrote:
    >> pemo said:
    >>
    >>> wrote:

    >> <snip>
    >>>> do_foo(&foo1,1);
    >>>> do_foo(&foo2,2);
    >>>
    >>> &foo1 etc have the type pointer to pointer to function [...], so you
    >>> should remove the &.

    >>
    >> I agree that the & is ugly and unnecessary, but you're wrong about
    >> the type.
    >>
    >> The function pointer foo1 can be expressed as &foo1 too; they are both
    >> "pointer to function". It's a bug-ugly wart, but it's true.

    >
    > Thanks for the correction Richard - very interesting! Don't suppose you
    > have a handy ref into the standard?


    3.2.2.1 of C89 draft.
    6.3.2.1[#4] of N869.
    6.3.2.1[#4] of C99 final.

    Basically, they all say the same thing: an expression of function type is
    automagically converted into an expression of type "pointer to function"
    /except/ when handed to '&' (or one other edge case, sizeof, which we're
    not discussing here); this is because '&' gives you the pointer /anyway/ -
    in fact, the conversion is like an invisible implicit '&', which a visible,
    explicit '&' replaces.



    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, May 11, 2006
    #5
  6. pemo Guest

    pemo wrote:
    > Richard Heathfield wrote:
    >> pemo said:
    >>
    >>> wrote:

    >> <snip>
    >>>> do_foo(&foo1,1);
    >>>> do_foo(&foo2,2);
    >>>
    >>> &foo1 etc have the type pointer to pointer to function [...], so you
    >>> should remove the &.

    >>
    >> I agree that the & is ugly and unnecessary, but you're wrong about
    >> the type.
    >>
    >> The function pointer foo1 can be expressed as &foo1 too; they are
    >> both "pointer to function". It's a bug-ugly wart, but it's true.

    >
    > Thanks for the correction Richard - very interesting! Don't suppose
    > you have a handy ref into the standard?


    6.5.3.2 - 3

    Although the '+' mentioned there has me frowning a bit!

    --
    ==============
    Not a pedant
    ==============
     
    pemo, May 11, 2006
    #6
  7. Guest

    Richard Heathfield wrote:
    > pemo said:
    >
    > > wrote:

    > <snip>
    > >> do_foo(&foo1,1);
    > >> do_foo(&foo2,2);

    > >
    > > &foo1 etc have the type pointer to pointer to function [...], so you
    > > should remove the &.

    >
    > I agree that the & is ugly and unnecessary, but you're wrong about the type.
    >
    > The function pointer foo1 can be expressed as &foo1 too; they are both
    > "pointer to function". It's a bug-ugly wart, but it's true.
    >
    >
    > --
    > Richard Heathfield
    > "Usenet is a strange place" - dmr 29/7/1999
    > http://www.cpax.org.uk
    > email: rjh at above domain (but drop the www, obviously)


    Thanks for the tip. Is the code otherwise OK?
     
    , May 11, 2006
    #7
  8. Thad Smith Guest

    wrote:
    > I love this place. This one problem keeps coming back to bite me.
    > Suppose I have the following situation (actually I do).
    >
    > func1()
    > {
    > codeA
    > somefunc1()
    > codeB
    > }
    >
    > func2()
    > {
    > codeA
    > somefunc2()
    > codeB
    > }
    >
    > func3()
    > {
    > codeA
    > somefunc3()
    > codeB
    > }
    >
    > I'm trying to follow the DRY school of thought and simplify this down
    > to one function. Sometimes I just use macros, but it's just awful.


    In order to Don't Repeat Yourself, you sometimes need to create
    additional functions or macros. Here are some options to not repeating
    codeA and codeB:

    1. Make codeA and codeB into separate functions.
    func1() {
    codeA();
    somefunc1();
    codeB();
    }
    etc.

    The potential problem with that is that if codeA and codeB share
    variables, you have to either pass them as parameters or make them
    shared variables.

    2. Write wrapper functions to somefuncx() that have a common interface.
    wrapsomefunc1(a,b,c,d,e) {
    somefunc1(a,b);
    }

    You can then pass a pointer to the wrapper functions.

    3. Pass a selection parameter, as you suggested.
    func(int opt) {
    codeA;
    switch(opt) {
    case 0: somefunc1(a,b); break;
    case 1: somefunc2(b,c,d,e); break;
    case 2: somefunc3(c); break;
    }
    codeB;
    }

    This is the tidiest technique, but func() must have the details for all
    the options.

    --
    Thad
     
    Thad Smith, May 13, 2006
    #8
  9. On 10 May 2006 23:16:38 -0700, wrote:

    > I love this place. This one problem keeps coming back to bite me.
    > Suppose I have the following situation (actually I do).
    >
    > func1()
    > {
    > codeA
    > somefunc1()
    > codeB
    > }
    >
    > func2()
    > {
    > codeA
    > somefunc2()
    > codeB
    > }
    >
    > [etc.] The trouble is
    > those inner functions don't always take the same number of parameters.
    > I could make arbitrary structures to contain all the parameters into he
    > void pointer, but in my opinion, making single use structures to lump
    > arbitrary data together is worse than the macro method.
    >
    > So, next I tried this.
    >
    > #include <stdio.h>
    >
    > void foo1(int a)

    <snip>
    > void foo2(int a, int b)

    <snip>
    > void do_foo(void (*foo)(), int opt)
    > {
    > if(opt == 1)
    > foo(5);
    > else if(opt == 2)
    > foo(5,10);
    > }
    >
    > int main(void)
    > {
    > do_foo(&foo1,1);
    > do_foo(&foo2,2);
    > return 0;
    > }
    >
    > I'm using opt to choose the function definition. It's a bit ugly, but
    > I'm ok with it. I'm just not sure if it's legal. I see lots of "don't
    > ever do this" when I google for unspecified function arguments.
    >

    It is definitely legal as long as the (various) callees take only
    'K&R1 compatible' arguments, that is:
    - not varargs
    - not prototyped parameters narrower than int (flavors of char or
    short, or in C99 possibly impl-specific) or double (float)
    - and all return the same type (here, void)

    and the actual args in the chosen call, after (only) the default
    promotions, match the actual parameter types in a prototyped
    definition or the promoted types in a nonprototyped definition.

    And if you get any of this wrong, either initially or years down the
    road after umpteen changes, the implementation is not required to
    detect your mistake, and damn few if any will, instead you get
    Undefined Behavior which can be arbitrarily bad -- the canonical
    example here being nasal demons -- and in this (unlike some other
    common UBs) is likely a crash or serious data corruption.

    Personally I think that danger outweighs the reduction in code
    duplication, which can be achieved by other means if necessary. But
    it's your choice. (Or that of your boss/clients/customers/users.)

    > So anyway, c gurus, what is the smart way to handle this? And what do
    > you think about closures in C, um, 2009 (just kidding)?


    <OT>If I just want some safely shared context I'll use C++ related
    classes or function objects, link compatible and (mostly) tool &
    practice compatible on all systems of interest to me. If I really want
    downward closures I'll probably use Ada or Pascal, generally link
    compatible with C and C++. If I actually want upward closures, I've
    got more restricted choices.</>

    C is what it is. If it ain't broke don't fix it.


    - David.Thompson1 at worldnet.att.net
     
    Dave Thompson, May 22, 2006
    #9
    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. Shawn
    Replies:
    2
    Views:
    725
    Rob Dekker
    Feb 27, 2006
  2. Robert

    Simplifying HTML code

    Robert, Nov 30, 2004, in forum: HTML
    Replies:
    7
    Views:
    519
    Jim Michaels
    Feb 1, 2006
  3. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    682
  4. Tim Menninger

    Simplifying Soap Web Services calls for client code

    Tim Menninger, Oct 31, 2003, in forum: ASP .Net Web Services
    Replies:
    1
    Views:
    241
    Paolo
    Nov 11, 2003
  5. Replies:
    1
    Views:
    82
Loading...

Share This Page