Chame uma function nomeada em uma variável de string em C

Eu quero chamar uma function usando uma variável. Isso é possível em C?

Na verdade, o que eu quero fazer é pegar o nome da function do usuário e armazená-lo em uma variável. Agora quero chamar a function que tem seu nome armazenado. Alguém pode me dizer como isso pode ser feito em C?

Eu quero desenvolver um mecanismo de jogo AI para um jogo de dois jogadores. Dois programas sem function principal que implementam a lógica para ganhar o jogo serão alimentados no motor do jogo. Deixe-me ser claro que os nomes dos programas serão os mesmos que os das funções privilegiadas do programa que implementam a lógica para ganhar o jogo.

Então, quando o usuário digita o nome do primeiro e do segundo jogador, posso armazená-lo em duas variables ​​diferentes. Agora, como os nomes das funções primárias são os mesmos dos nomes dos programas, pretendo chamar as funções com variables ​​contendo os nomes dos programas.

C não suporta este tipo de operação (linguagens que possuem reflection). O melhor que você será capaz de fazer é criar uma tabela de pesquisa de nomes de function para pointers de function e usá-la para descobrir qual function chamar. Ou você poderia usar uma instrução switch.

O melhor que você pode fazer é algo assim:

 #include  // functions void foo(int i); void bar(int i); // function type typedef void (*FunctionCallback)(int); FunctionCallback functions[] = {&foo, &bar}; int main(void) { // get function id int i = 0; scanf("%i", &i); // check id if( i >= sizeof(functions)) { printf("Invalid function id: %i", i); return 1; } // call function functions[i](i); return 0; } void foo(int i) { printf("In foo() with: %i", i); } void bar(int i) { printf("In bar() with: %i", i); } 

Isso usa números em vez de strings para identificar as funções, mas fazê-lo com strings é simplesmente uma questão de converter a string na function apropriada.

O que você está fazendo exatamente? Se apenas por curiosidade, aqui vai você, mas se você está tentando resolver um problema com isso, eu tenho certeza que há uma forma mais adequada para a sua tarefa.

Editar

No que diz respeito à sua edição, você vai querer ir com a resposta do onebyone , com certeza.

Você deseja que seus usuários construam bibliotecas dinâmicas (isso é um object compartilhado [.so] no Linux, e uma biblioteca de links dynamics [.dll] no Windows).

Depois de fazer isso, se eles fornecerem o nome da biblioteca, você poderá solicitar que o sistema operacional carregue essa biblioteca e solicite um ponteiro para uma function dentro dessa biblioteca.

Enquanto isso não é exatamente uma solução prática, eu aposto que você poderia certamente chamar uma function por uma string, tendo um programa lido em seu próprio executável e analisando a tabela de símbolos. A tabela de símbolos deve conter o nome da function, assim como seu primeiro endereço de instrução. Você poderia então colocar este endereço em uma variável de ponteiro de function e chamá-lo.

Eu acho que posso tentar acertar isso.

EDIT: Por favor, ninguém nunca escrever código real como este, mas aqui está como você pode chamar uma function usando uma seqüência de caracteres para um binário Linux ELF com uma tabela de símbolos intactos (requer libelf):

 #include  #include  #include  #include  #include  #include  void callMe() { printf("callMe called\n"); } int main(int argc, char **argv) { Elf64_Shdr * shdr; Elf64_Ehdr * ehdr; Elf * elf; Elf_Scn * scn; Elf_Data * data; int cnt; void (*fp)() = NULL; int fd = 0; /* This is probably Linux specific - Read in our own executable*/ if ((fd = open("/proc/self/exe", O_RDONLY)) == -1) exit(1); elf_version(EV_CURRENT); if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { fprintf(stderr, "file is not an ELF binary\n"); exit(1); } /* Let's get the elf sections */ if (((ehdr = elf64_getehdr(elf)) == NULL) || ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) || ((data = elf_getdata(scn, NULL)) == NULL)) { fprintf(stderr, "Failed to get SOMETHING\n"); exit(1); } /* Let's go through each elf section looking for the symbol table */ for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); cnt++) { if ((shdr = elf64_getshdr(scn)) == NULL) exit(1); if (shdr->sh_type == SHT_SYMTAB) { char *name; char *strName; data = 0; if ((data = elf_getdata(scn, data)) == 0 || data->d_size == 0) { fprintf(stderr, "No data in symbol table\n"); exit(1); } Elf64_Sym *esym = (Elf64_Sym*) data->d_buf; Elf64_Sym *lastsym = (Elf64_Sym*) ((char*) data->d_buf + data->d_size); /* Look through all symbols */ for (; esym < lastsym; esym++) { if ((esym->st_value == 0) || (ELF64_ST_BIND(esym->st_info)== STB_WEAK) || (ELF64_ST_BIND(esym->st_info)== STB_NUM) || (ELF64_ST_TYPE(esym->st_info)!= STT_FUNC)) continue; name = elf_strptr(elf,shdr->sh_link , (size_t)esym->st_name); if(!name){ fprintf(stderr,"%sn",elf_errmsg(elf_errno())); exit(-1); } /* This could obviously be a generic string */ if(strcmp("callMe", name) == 0 ) { printf("Found callMe @ %x\n", esym->st_value); fp = esym->st_value; } } /* Call and hope we don't segfault!*/ fp(); elf_end(elf); return 0; } 

Não é possível em C puro, no entanto você pode ser capaz de jogar truques com dlls. Coloque todas as funções que você deseja selecionar em uma dll, em seguida, use dlsym (ou GetProcAddress no Windows, ou qualquer outra API seu sistema oferece) para obter o ponteiro de function pelo nome e chamar usando isso.

Isso não funciona em algumas plataformas, seja porque elas não têm dlls, ou porque, como o Symbian, as funções na dll não podem ser acessadas pelo nome em tempo de execução, apenas pelo número.

Esteja ciente de que, se o seu usuário o enganar para selecionar uma function que não tenha os parâmetros corretos para a chamada que você deseja fazer, seu programa dará errado. C realmente não é projetado para lidar com esse tipo de coisa.

 #include  #include  void function_a(void) { printf("Function A\n"); } void function_b(void) { printf("Function B\n"); } void function_c(void) { printf("Function C\n"); } void function_d(void) { printf("Function D\n"); } void function_e(void) { printf("Function E\n"); } const static struct { const char *name; void (*func)(void); } function_map [] = { { "function_a", function_a }, { "function_b", function_b }, { "function_c", function_c }, { "function_d", function_d }, { "function_e", function_e }, }; int call_function(const char *name) { int i; for (i = 0; i < (sizeof(function_map) / sizeof(function_map[0])); i++) { if (!strcmp(function_map[i].name, name) && function_map[i].func) { function_map[i].func(); return 0; } } return -1; } int main() { call_function("function_a"); call_function("function_c"); call_function("function_e"); } 

Como dito por outros, é verdade que C não tem mecanismo de reflection. Mas você pode conseguir esse tipo de comportamento usando biblioteca carregada dinâmica / object compartilhado. Na verdade, você pode carregar uma biblioteca dinâmica e, em seguida, você pode chamar as funções na dll / so com seu nome! Não é específico para C e OS, mas é o caminho. Ele usa o dlopen no Linux e no LoadLibrary no Windows. Você pode encontrar bibliotecas que fazem o trabalho para você como o gtk / glib .

É isso que você está tentando?

 void foo() { printf("foo called\n"); } void bar() { printf("bar called\n"); } int main() { char fun[10] = {'\0'}; printf("Enter function name (max 9 characters):"); scanf("%s",fun); if(strcmpi(fun, "foo") == 0) { foo(); } else if(strcmpi(fun, "bar") == 0) { bar(); } else { printf("Function not found\n"); } return 0; } 

Se eu entendi sua pergunta corretamente, você quer usar binding tardia para chamar uma function C. Isso não é algo que você normalmente pode fazer em C. Nomes simbólicos (como nomes de funções) não são armazenados no código gerado pelo compilador C. Você provavelmente poderia deixar o compilador emitir símbolos e usá-los para executar a binding tardia, mas a técnica variaria de compilador para compilador e provavelmente não valeria a pena.

Idiomas como C # e Java suportam reflection, facilitando a execução da binding tardia.

Eu apenas tentei a abordagem de Steve Jessop usando uma biblioteca vinculada estaticamente como sugerida por Williham Totland nos comentários e acabou sendo não-trivial.

Em primeiro lugar, você encontrará um monte de lugares na Web (incluindo a Wikipedia) que lhe dirão que a maneira de abrir seu programa principal como uma biblioteca é chamar dlopen (3) como este dlopen(NULL, 0) . Isso não funcionará para a glibc porque um sinalizador de binding deve ser especificado, como a página man afirma claramente:

Um dos dois valores a seguir deve ser incluído na sinalização:
RTLD_LAZY
Execute binding preguiçosa. Resolva apenas símbolos como o código …
RTLD_NOW
Se este valor for especificado ou a variável de ambiente …

Eu não acho que você escolhe o assunto aqui porque você vai ligar todos os símbolos da biblioteca estática em seu executável.

Isso nos leva ao próximo problema. O vinculador não includeá os símbolos de sua biblioteca estática em seu executável porque eles não são referenciados . A maneira de forçar o linker GNU a include os símbolos de qualquer forma é -Wl,--whole-archive path/to/static/lib.a -Wl,--no-whole-archive como descreve a resposta. A maneira de forçar o vinculador do Mac OS X a include todos os símbolos de sua biblioteca estática é -Wl,-force_load path/to/static/lib.a

C arrays só podem ser indexados com tipos integrais. Portanto, escreva uma cadeia de mapeamento de tabela de hash para funcionar com pointers.

Também pode valer a pena examinar o recurso em Python, Lua e outras linguagens de script para incorporar seu tempo de execução em um programa em C: partes do código em C podem ser manipuladas com a linguagem de script.

Alt’ly, algumas pessoas codificam extensões de linguagem de script em C. Então elas podem ter a velocidade e o baixo nível de access de C em seus scripts.

Você descobrirá, mais cedo ou mais tarde, que usar expressões idiomáticas de linguagem de script dinamicamente – como eval (), e a linha embaçada entre function e nome da function e código que depende de matrizes assoc – em C é possível mas doloroso.

Apresentando a function Nginx-c. É um módulo NGINX que permite vincular seu aplicativo .so (c / c ++) no contexto do servidor e chamar a function de aplicação .so na diretiva location. Você pode implementar o cache de dados de memory compartilhada nginx através da function nginx c ( https://github.com/Taymindis/nginx-c-function/wiki/Nginx-Cache-Data-via-nginx-c-function ). Isto é para o desenvolvedor que ama hospedar o servidor c. https://github.com/Taymindis/nginx-c-function

insira a descrição da imagem aqui