简体   繁体   中英

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

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

C++ doesn't have reflection so you must hack it, ie:

#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;
}

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.

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:

#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" );
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM