Is there C/C++ equivalent of eval(“function(arg1, arg2)”)?

后端 未结 5 412
一个人的身影
一个人的身影 2020-11-30 07:41

it need a way to call function whose name is stored in a string similar to eval. Can you help?

相关标签:
5条回答
  • 2020-11-30 08:05

    Except using the function map in the program and hack it on the Makefile, you can access it through ELF.

    I think this method is better as it did not need to write duplicate code and compile it every time on different machine.

    Here is my demo C/C++ equivalent of eval(“function(arg1, arg2)”)

    #include<stdio.h>
    #include<stdlib.h>
    #include<elf.h>
    #include<libelf.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<gelf.h>
    #include<string.h>
    
    void my_fun()
    {
        int a = 19;
        printf("my_fun is excute, a is %d \n", a);
    }
    
    void my_fun2()
    {
        printf("my_fun2 is excute\n");
        return;
    }
    
    void my_fun3()
    {
        return;
    }
    
    void excute_fun(char *program_name, char *function_name)
    {
        int i, count;
        Elf32_Ehdr *ehdr;
        GElf_Shdr   shdr;
        Elf *elf;
        Elf_Scn *scn = NULL;
        Elf_Data *data;
        int flag = 0;
        int fd = open(program_name, O_RDONLY);
        if(fd < 0) {
            perror("open\n");
            exit(1);
        }
        if(elf_version(EV_CURRENT) == EV_NONE) {
            perror("elf_version == EV_NONE");
            exit(1);
        }
        elf = elf_begin(fd, ELF_C_READ, (Elf *) NULL);
        if(!elf) {
            perror("elf error\n");
            exit(1);
        }
        /* Elf32_Off e_shoff; */
        /* if ((ehdr = elf32_getehdr(elf)) != 0) { */
        /*     e_shoff = ehdr->e_shoff; */
        /* } */
        /* scn = elf_getscn(elf, 0); */
        /* printf("e_shoff is %u\n", e_shoff); */
        /* scn += e_shoff; */
        while ((scn = elf_nextscn(elf, scn)) != NULL) {
            gelf_getshdr(scn, &shdr);
            if (shdr.sh_type == SHT_SYMTAB) {
                /* found a symbol table. */
                break;
            }
        }
        data = elf_getdata(scn, NULL);
        if(!shdr.sh_entsize)
            count = 0;
        else
            count = shdr.sh_size / shdr.sh_entsize;
        for (i = 0; i < count; ++i) {
            GElf_Sym sym;
            gelf_getsym(data, i, &sym);
            char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
            if(sym_name != NULL && sym_name[0] != '_' && sym_name[0] != '\0' && sym_name[0] != ' ' && sym.st_value != 0)
            {
                /* printf("sym_name is %s\n", sym_name); */
                /* printf("%s = %X\n", elf_strptr(elf, shdr.sh_link, sym.st_name), sym.st_value); */
                if(!strcmp(sym_name, function_name)) {
                    void (*fun)(void) = (void*)sym.st_value;
                    (*fun)();
                    flag = 1;
                }
            }
        }
        if(!flag)
            printf("can not find this function\n");
    
        elf_end(elf);
        close(fd);
    }
    
    int main(int argc, char *argv[])
    {
        char *input = (char*)malloc(100);
        for(;;) {
            printf("input function_name to excute: ");
            scanf("%s", input);
            excute_fun(argv[0], input);
            memset(input, 0, sizeof(input));
            printf("\n");
        }
        free(input);
        return 0;
    }
    

    This implementation is based on Example of Printing the ELF Symbol Table

    0 讨论(0)
  • 2020-11-30 08:12

    There are at least 2 alternatives:

    • The command pattern.
    • On windows, you can use GetProcAddress to get a callback by name, and dlopen + dlsym on *nix.
    0 讨论(0)
  • 2020-11-30 08:13

    You could try to adopt an existing scripting engine, expose the functions you like to this and then use this to evaluate your statements. One such enging could be the V8 engine: https://developers.google.com/v8/intro but there are many alternatives and different languages to choose from.

    Here are some examples:

    • Boost Python
    • V8
    • LUA
    • AngelScript
    0 讨论(0)
  • 2020-11-30 08:19

    C++ doesn't have reflection so you must hack it, i. e.:

    #include <iostream>
    #include <map>
    #include <string>
    #include <functional>
    
    void foo() { std::cout << "foo()"; }
    void boo() { std::cout << "boo()"; }
    void too() { std::cout << "too()"; }
    void goo() { std::cout << "goo()"; }
    
    int main() {
      std::map<std::string, std::function<void()>> functions;
      functions["foo"] = foo;
      functions["boo"] = boo;
      functions["too"] = too;
      functions["goo"] = goo;
    
      std::string func;
      std::cin >> func;
      if (functions.find(func) != functions.end()) {
        functions[func]();
      }
      return 0;
    }
    
    0 讨论(0)
  • 2020-11-30 08:23
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    using namespace std;
    
    
    double eval( string expression );
    
    
    int main( int argc, char *argv[] )
    {
        string expression = "";
        for ( int i = 1; i < argc; i++ )
        {
           expression = expression + argv[i];
        }
        cout << "Expression [ " << expression << " ] = " << endl;
    
        eval( expression );
    }
    
    
    double eval( string expression )
    {
        string program = "";
        program = program + "#include <cmath>\n";
        program = program + "#include <iostream>\n";
        program = program + "using namespace std;\n";
        program = program + "int main()\n";
        program = program + "{\n";
        program = program + "   cout << ";
        program = program + expression;
        program = program + " << endl;\n";
        program = program + "}";
    
    
        ofstream out( "abc.cpp" );
        out << program;
        out.close();
    
        system( "g++ -o abc.exe abc.cpp" );
        system( "abc" );
    }
    
    0 讨论(0)
提交回复
热议问题