Function returning a function - in C



  • Hello everybody!

    I already use callbacks a lot; for that I normally define a type

        typedef int (callback_t)(int);
        struct struct_t { callback_t *after_processing; };
        callback_t F;
        int F(int i) { ... }

    and use that type for my variables, structure and function declarations, as above.
    So far, so good.

    Now I got the idea that I'd like to try returning a function address from a function; while that works for the first level, I can't make it work recursively.
    I can define the function as returning a (void*), assign the value to a variable and call that - but is there some other way?

    • Trying typedef callback_t* (callback_t)(int) or similar doesn't work - callback_t isn't defined at the first occurrence, but only at the second - where gcc already emitted an error.
    • Structures or unions can be pre-declared, so that you can use pointers to them; but there's no way for functions, is there?

    I got as far as this:

         #include <stdio.h>
    
     typedef void (*callback_t1)(int);
     typedef callback_t1* (callback_t2)(int);
     typedef callback_t2* (callback_t3)(int);
     typedef callback_t3* (callback_t4)(int);
     
     callback_t4 X;
     callback_t3 *X(int i)
     {
        printf("(%d) ", i);
        return i>0 ? X(i-1) : X;
     }
     
     int main(void)
     {
        printf("%p\n", X);
        printf("%p\n", X(2));
        printf("%p\n", X(3)(4));
        printf("%p\n", X(5)(6)(7));
     }
    

    but that's ugly - I have to change the type definitions for an additional level.

    Does someone know a trick?



  • I'm not sure if there's a way to do exactly what you want, but you can enclose the function pointer in a struct and be happy:

    
    #include <stdlib.h>
    #include <stdio.h>
    
    struct container
    {
      struct container (* call)(int);
    };
    
    struct container look_I_return_myself(int p)
    {
      struct container result;
    
      printf("Here's some integer someone gave me, not sure what to do with it: %d.\n", p);
    
      result.call = look_I_return_myself;
      return result;
    }
    
    int main(void)
    {
      look_I_return_myself(3).call(4).call(5);
      return EXIT_SUCCESS;
    }
    
    

    Also, it looks like the [ code ] BBcode turns "\n" into a real linebreak. WTF?



  • @Spectre said:

    struct container look_I_return_myself(int p)
    {
    struct container result;

    printf("Here's some integer someone gave me, not sure what to do with it: %d.\n", p);

    result.call = look_I_return_myself;
    return result;
    }

     

    Does that actually work the way it's written? I'm asking because I don't use C all that often, and I'm thinking that the struct would be allocated on the stack, then filled, then a pointer to the stack is returned. As part of the return, the stack pointer is set back to that of the calling function, with the return value on the top of the stack.

    The pointer is pointing into currently free stack space, but the space may be used for local variables at any time, which would corrupt the struct that's being pointed to. Then, when the struct is accessed, you jump to an incorrect memory address and end up with anything from a null pointer exception to arbitrary code execution.

    It seems to me that anything returned by a function should be a basic type or allocated on the heap and return a pointer. 



  • @Nandurius said:

    Does that actually work the way it's written? I'm asking because I don't use C all that often, and I'm thinking that the struct would be allocated on the stack, then filled, then a pointer to the stack is returned.
    That's where you're wrong. A copy of the struct is returned. So everything's okay.



  • @bstorer said:

    That's where you're wrong. A copy of the struct is returned. So everything's okay.
     

    Thank you! That makes sense, I wasn't sure if the compiler could actually copy structures on its own, but I suppose it's entirely static and known at compile time in C. I've been using Java for too long where everything is passed by reference :)



  • > I'm not sure if there's a way to do exactly what you want, but you can enclose the function pointer in a struct and be happy:

    Thank you, that's a nice idea. Although the .call part isn't that aesthetical :-), and that a temporary (struct) is needed is no advantage over the (void*) variable ...

    But a good idea, thank you.



  •  Does this help ?



  • @Nelle said:

     Does this help ?

    Not really, because
    1. That solution is essentially what Spectre proposed.
    2. That solution's in C++, while Spectre's is in C, which is what was asked for.



  • If you want the function to return a pointer to itself rather than a structure containing that pointer, you can do that too:

    typedef void (*callback_t)(void);

    callback_t look_i_return_myself(int n) {

    printf("%d\n");

    return look_i_return_myself;

    }

    int main(int argc, char *argv[]) {


    look_i_return_myself(1)(2)(3);


    return 0;


    }

    If you don't want a typedef, just take what you'd typedef, remove the name, and make that your return type:

    void (*)(void) look_i_return_myself(int n) {


    ...


    }


    ...

    By the way, how do I disable HTML in posts? When I press return, it doesn't make newlines in the final post.



  • @joeyadams said:

    If you want the function to return a pointer to itself rather than a structure
    containing that pointer, you can do that too:

    ~SNIP~

    Well... except it doesn't work. Have you tested it?

    @joeyadams said:

    By the way, how do I disable HTML in posts? When I press return, it doesn't
    make newlines in the final post.

    In your profile, there's a setting which editor to use.



  • >If you want the function to return a pointer to itself rather than a structure containing that pointer, you can do that too:

    Well... except it doesn't work. Have you tested it?

    Yes, I realized that :) I couldn't edit my post after some time expired, and frankly, I was tired of messing with it :)

    In your profile, there's a setting which editor to use. In your profile, there's a setting which editor to use.

    I changed that setting to "Plain Text", but I still have to put HTML <p>s for return characters.



  • @joeyadams said:

    I changed that setting to "Plain Text", but I still have to put HTML <p>s for return characters.
     

    Plain text requires you to put in your own line breaks. That should be obvious. Enable the standard editor for automatic linebreaks.

    If the standard editor doesn't work, make sure you are not using opera, you are allowing time for the editor to load (you should see the toolbar on the editor when it has loaded). Also, make sure you are not block javascript and stuff with noscript.



  • @MasterPlanSoftware said:

    Plain text requires you to put in your own line breaks. That should be obvious. Enable the standard editor for automatic linebreaks.

    If the standard editor doesn't work, make sure you are not using opera, you are allowing time for the editor to load (you should see the toolbar on the editor when it has loaded). Also, make sure you are not block javascript and stuff with noscript.

     

    a straight and helpfull answer, not arrogant, not agressive, no insults, bashing ...

    who are you and what did you do to MasterPlanSoftware ?



  • @Nelle said:

    a straight and helpfull answer, not arrogant, not agressive, no insults, bashing ...

    who are you and what did you do to MasterPlanSoftware ?

     

    Maybe it is because he is a decent poster so far and I would only be mean to someone who was a cocky, arrogant retard?



  • @joeyadams said:

    If you want the function to return a pointer to itself rather than a structure containing that pointer, you can do that too:



    I know it's old post, but I've just stumbled upon it.



    what you'd need is to cast there and back between two pointers, what quite sux...


    #codeBegin-
    #include <stdio.h>
    typedef void (*univ_t)(void);
    typedef univ_t (*loc_f)(int);
    
    univ_t look_maam_i_ret_me(int i) {
      printf ("random crap: %d\n", i);
      return (univ_t)&look_maam_i_ret_me;
    }
    
    int main()
    {
      ((loc_f)((loc_f)((loc_f)look_maam_i_ret_me(1))(2))(3))(4);
    
      return 1;
    }
    #codeEnd-
    

    This is correct since the standard says, that pointer should be correct, if you cast-it-back to proper function pointer.
    Looks kinda lispish ;->

    and here is result on codepad

    It'd be even cleaner if you could cast pointer to function to void* pointer, but that's not allowed


  • C-FAQ is your friend, and it talks about both the struct form and the pointer casting form mentioned above (which are both valid solutions):

    c-faq.com

    (Incidentally, I was amused to try out the simple void (*f)(int) (int i){ printf("f(%d)\n",i); return f;} case and get the compiler error: "Error: 'f' declared as function returning a function". You learn something new every day!


Log in to reply