Thread: Calling a function named in a variable.

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    19

    Calling a function named in a variable.

    I looked. I really did. Anyway...

    Is it possible in c++ to call a function the name of which is contained in a variable?

    Psuedo code (which is a euphemism for I can't write code that works):

    Code:
    double MYROUTINE(double x){
    //  do stuff
    }
    
    double MYBOSSESROUTINE(const char* z)
    {
     // value of z is "MYROUTINE"
         call z // <== obviously that doesn't work
    }
    Thanks

    John

  2. #2
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    You can use function pointers.
    Code:
    typedef double (*SOME_FN)(double);
    
    double MYROUTINE(double x) {
    //  do stuff
    }
    
    double MYBOSSESROUTINE(SOME_FN z)
    {
        return z(1.0);
    }
    int main(void)
    {
        MYBOSSESROUTINE(MYROUTINE);
    }
    bit∙hub [bit-huhb] n. A source and destination for information.

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    19

    Maybe I'm not understanding

    I can't change the signature of MYBOSSESROUTINE from:

    double MYBOSSESROUTINE(const char* z)

    to

    double MYBOSSESROUTINE(SOME_FN z)

    All I'm allowed to do is pass him a string with the name of my function.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    On Windows you would use GetModuleHandle()/GetProcAddress(). On Linux you would use dlopen()/dlsym(). The function in question must be exported dynamically for it to work.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Registered User
    Join Date
    Mar 2011
    Posts
    19
    Whoosh! That was the sound of your solution wizzing past my head.

    First, it is a windows environment.

    Second, while I can read documentation as good as the next fella, pseudocode (even BROKEN pseudocode that I can test and report the errors) is always appreciated.

    I have no problem with the function being exported (if'n I knew how to accomplish that). I imagine that requires a statement something like:

    #COMPILERCOMMAND EXPORTME

    I'm off to read up on GetModuleHandle()/GetProcAddress().

    Thanks

    John

  6. #6
    Registered User
    Join Date
    Mar 2011
    Posts
    546
    there isn't a way to do that natively in the C or C++ language. there is no standard method of introspection, which is what you need. in java for example there are ways to do that.

    extending on what bithub said, one way to accomplish that natively is to have a table that associates the function name with the function address in a function pointer, then search for the name and then call the address via the function pointer. the drawback is this means you have to know in advance the names of the functions you want to call so you can put them in the table.

    In fact this is what the getmodulehandle/getprocaddress stuff does for you behind the scenes, although that approach doesn't require you to know the names in advance so it is more complete but platform specific.

    example

    Code:
    // note : probably won't compile.
    
    typedef double (*SOME_FN)(double);
    struct function {
        const char *name;
        SOME_FN    f;
    };
    
    function function_list[] = {
    {"MYROUTINE",MYROUTINE},
    {0,0}
    };
    
    SOME_FN find_function_by_name(const char *name)
    {
            function *p = function_list;
            // iterate for an element in function_list that matches 'name' or 'not found'
            // ....
    
           // call via the function pointer found
           return p->f;
    }
    
    double MYBOSSESROUTINE(const char* z)
    {
    SOME_FN f = find_function_by_name(z);
    
    return (*SOME_FN)(1.0);
    }

  7. #7
    Registered User
    Join Date
    Mar 2011
    Posts
    19
    I'm not having much luck with understanding how to implement the GetModuleHandle()/GetProcAddress() solution.

    I appreciate the suggestion of the internal table, it may very well be a compromise between what I originally wanted: a switch statement and a dynamic solution (which my boss wants).

    Seems a shame that there isn't a built in mechanism to deal with data matching a process. If I'm working with a WIDGET, then I should be able to say something like DO WIDGET to get my result. Such is life.

    I'll keep working with the GetModuleHandle()/GetProcAddress() solution because someday, I want to separate myself from working on or in my boss's function and, at the same time, limit my efforts to that which is within my routine.

    I know that your suggestion accomplishes the first half of the goal.

    Thanks.

    John

  8. #8
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Quote Originally Posted by JohnAnon View Post
    I'm not having much luck with understanding how to implement the GetModuleHandle()/GetProcAddress() solution.

    I appreciate the suggestion of the internal table, it may very well be a compromise between what I originally wanted: a switch statement and a dynamic solution (which my boss wants).

    Seems a shame that there isn't a built in mechanism to deal with data matching a process. If I'm working with a WIDGET, then I should be able to say something like DO WIDGET to get my result. Such is life.

    I'll keep working with the GetModuleHandle()/GetProcAddress() solution because someday, I want to separate myself from working on or in my boss's function and, at the same time, limit my efforts to that which is within my routine.

    I know that your suggestion accomplishes the first half of the goal.

    Thanks.

    John
    Its possible, you just have to implement it. Meaning that you will have something like:
    Code:
    double MYROUTINE(double x){
          //  do stuff
          // register routine
    }
    
    double MYBOSSESROUTINE(const char* z)
    {
         // value of z is "MYROUTINE"
         Call(z)(); // or something like that
    }
    Think that if there was a built in system it will more or less do something like above, just maybe more efficiently.

    There are a few ways to make this elegant. One is to use std::map. They key will be a string and the value will actually be a function pointer. Then you will do something like:
    Code:
    //define a function pointer
    typedef double (*fnc_ptr)(double x);
    //this will be your function registry
    std::map<std::string, fnc_ptr> fncRegistry; 
    
    //maybe this is not actually needed
    double MYROUTINE_A(double x);
    
    double MYROUTINE_A(double x)
    {
       fncRegistry("MYROUTINE_A", MYROUTINE_A);
       //define the function
    }
    
    double MYBOSSESROUTINE(const char* z)
    {
       ....
       fncRegistry(z)(10.2); //call z
       ....
    }
    So you do exactly what you want to do very nicely

    Note that you can also register functions that belong to a library
    Code:
    #include <math.h>
    
    //as above
    
    int main()
    {
         fncRegistry.insert(std::pair<std::string, fnc_ptr>("cos", cos)); //register
         MYBOSSESROUTINE("cos");
    }
    so the solution is indeed dynamic. You just have to register all the functions that are going to be used.

    In other languages there are run-time solutions to get a name of a method. But the cases actually really needed are a few, usually a good design will solve your problems.

    Note that the functions has to return double and get one input as double. You can extend this with more code. Note also that if the function is misspelled, it will crash. You can fix this by making a "Call(...)" function that checks if the name exists or not first etc

    EDIT: This is sample code. Something might not compile, but you fix this with a few tweaks
    Last edited by C_ntua; 03-25-2011 at 07:56 PM.

  9. #9
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by JohnAnon View Post
    I'm not having much luck with understanding how to implement the GetModuleHandle()/GetProcAddress() solution.
    Post the code you're trying to use. Is it anything like the example on MSDN? GetProcAddress Function (Windows)
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  10. #10
    Registered User
    Join Date
    Mar 2011
    Posts
    19
    Yes, I'm trying to decipher the code in the example on MSDN. It is late here and it will take me too long to dig out the lines I've interspersed with my other code into a workable display.

    I'll try to do that tomorrow.

    Thanks for helping.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Here is example code:
    Code:
    #include <boost/scope_exit.hpp>
    
    typedef double (FncPtr_t)(const char*);
        auto hLibrary = LoadLibrary("JohnAnonsLibrary.dll"); // Opens the DLL and returns a handle to it
        BOOST_SCOPE_EXIT( (hLibrary) )
        {
            FreeLibrary(hLibrary); // We must free the library when we're done
        }
        BOOST_SCOPE_EXIT_END;
    
        auto MyFnc = reinterpret_cast<FncPtr_t>(GetProcAddress(hLibrary, "My function name"); // Find and return a function pointer to the specified function
        if (MyFnc == NULL)
            ; // Failure. Unable to find the specified function. 
        MyFunc(100.0); // Call the function
        // We're done. No need to do anything more. Boost.ScopeExit will take care of freeing the library for us.
    The code relies on Boost and C++0x. That means you need Visual C++ 10 or GCC 4.3 or higher.
    Code uses Boost with BOOST_SCOPE_EXIT which is a macro which will basically execute a chunk of code when a function ends. Very handy. If you don't have access to it, you have to call FreeLibrary manually at the end.
    You can replace "My function" with a string of your choice. In case it's a std::string, don't forget to call c_str() to get the C-style string.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Mar 2011
    Posts
    1
    very nice job......

  13. #13
    Registered User
    Join Date
    Mar 2011
    Posts
    19
    Unfortunately I'm stuck with VC++2008.

    Thanks, anyway.

    You know, based on the last few responses, I may have miscommunicated.

    I'm not building my own separate dll which my bosses routine will call.

    My code is going to be compiled at the same time and into the same dll/exe as his.

    Yes, I know this means that I can fiddle with a switch statement in his routine so that the passed value will call the correct routine of mine. But he is maintaining his routine and I'm responsible for maintaining my routines, even though they are in the same stream when compilation takes place.

    Sorry if I misled everybody.

    Does that make it easier or more difficult?
    Last edited by JohnAnon; 03-27-2011 at 08:55 PM.

  14. #14
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    Quote Originally Posted by JohnAnon View Post
    Unfortunately I'm stuck with VC++2008.

    Thanks, anyway.

    You know, based on the last few responses, I may have miscommunicated.

    I'm not building my own separate dll which my bosses routine will call.

    My code is going to be compiled at the same time and into the same dll/exe as his.

    Yes, I know this means that I can fiddle with a switch statement in his routine so that the passed value will call the correct routine of mine. But he is maintaining his routine and I'm responsible for maintaining my routines, even though they are in the same stream when compilation takes place.

    Sorry if I misled everybody.

    Does that make it easier or more difficult?
    Look at C_ntua's response then. It has what you're looking for.
    bit∙hub [bit-huhb] n. A source and destination for information.

  15. #15
    Registered User
    Join Date
    Mar 2011
    Posts
    19
    I had already done that since it looked both elegant and promising. On my computer, however, std::map returns compiler error "'map' is not a member of 'std'".

    Maybe I can get map from another library.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Pointers
    By MrMatt027 in forum C++ Programming
    Replies: 14
    Last Post: 12-10-2010, 04:32 PM
  2. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  3. Replies: 5
    Last Post: 01-13-2006, 12:00 AM
  4. Please Help - Problem with Compilers
    By toonlover in forum C++ Programming
    Replies: 5
    Last Post: 07-23-2005, 10:03 AM
  5. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM