在C中调用一个名为stringvariables的函数

我想用一个variables来调用一个函数。 在C中可能吗?

其实,我想要做的是,从用户获取函数名称,并将其存储在一个variables。 现在我想调用存储名称的函数。 任何人都可以告诉我如何在C中做到这一点?

我想开发一个双人游戏的AI游戏引擎。 两个没有实现获胜游戏逻辑的主要function的程序将被馈送到游戏引擎。 让我清楚的是,程序名称将与实现获胜游戏逻辑的程序中的主要function相同。

所以当用户input第一个和第二个玩家的名字时,我可以将它们存储在两个不同的variables中。 现在,由于primefunctionfunction名称与程序名称相同,我打算用包含prog名称的variables调用函数。

C不支持这种操作(有reflection的语言)。 你将能够做的最好的是创build一个从函数名到函数指针的查找表,并用它来确定要调用的函数。 或者你可以使用switch语句。

你能做的最好的是这样的:

 #include <stdio.h> // 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); } 

这使用数字而不是string来标识函数,但是用string来处理只是将string转换为适当的函数。

你到底在干什么? 如果只是为了好奇,在这里你可以去,但是如果你正在试图解决这个问题,我相信有一种更适合你的任务的方法。

编辑

关于你的编辑,你肯定会想一个人的答案。

您希望您的用户构builddynamic库(即Linux中的共享对象[.so]和Windows中的dynamic链接库[.dll])。

一旦你这样做,如果他们提供了你的库的名字,你可以要求操作系统为你加载这个库,并且请求一个指向这个库的函数的指针。

虽然这不是一个实际的解决scheme,但我敢打赌,你可以通过让程序读入自己的可执行文件并parsing符号表来确定调用函数。 符号表应该包含函数的名称以及它的第一个指令地址。 然后你可以把这个地址放在一个函数指针variables中并调用它。

我想我可以试着鞭打这件事。

编辑:请没有人写这样的真正的代码,但这里是如何调用一个string为一个完整的符号表的Linux ELF二进制文件的函数(需要libelf):

 #include <fcntl.h> #include <stdio.h> #include <elf.h> #include <libelf.h> #include <stdlib.h> #include <string.h> 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; } 

在纯粹的C中是不可能的,但是你也许可以用dll来玩技巧。 把你想要select的所有函数放到一个dll中,然后使用dlsym (或者Windows上的GetProcAddress ,或者你的系统提供的任何其他的API)来获得函数指针,然后使用它来调用。

这在某些平台上不起作用,要么是因为根本没有dll,要么是因为像Symbian一样,dll中的函数在运行时不能按名称访问,只能通过编号访问。

请注意,如果您的用户欺骗您select了一个没有正确参数的函数,那么您的程序就会出错。 C真的不是为了应付这种事情而devise的。

 #include <stdio.h> #include <string.h> 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"); } 

正如其他人所说,C没有任何反思机制。 但是你可以通过使用dynamic加载的库/共享对象来实现这种行为。 事实上,你可以加载一个dynamic库,然后你可以调用dll /所以他们的名字的function! 这不是C和OS的具体情况,但就是这样。 它在Windows上使用Linux和LoadLibrary上的dlopen。 你可以find像gtk / glib那样为你工作的库。

这是你正在尝试的:

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

如果我正确理解你的问题,你想使用后期绑定调用C函数。 这通常不能在C中完成。符号名称(如函数名称)不会存储在C编译器生成的代码中。 你也许可以让编译器发出符号,然后使用它们来执行后期绑定,但是这种技术在编译器和编译器之间会有所不同,并且可能不值得使用。

像C#和Java这样的语言支持reflection,因此可以很容易地执行后期绑定。

正如Williham Totland所build议的,我刚刚尝试了Steve Jessop的方法,使用了一个静态链接库,结果certificate这并不重要。

首先,你会发现networking上的一堆地方(包括维基百科)会告诉你,以库的forms打开你的主程序的方法就是像这个dlopen(NULL, 0)一样调用dlopen(3 dlopen(NULL, 0) 。 这不适用于glibc,因为必须指定一个绑定标志,正如手册页中明确指出的那样:

标志中必须包含以下两个值之一:
RTLD_LAZY
执行延迟绑定。 只parsing符号作为代码…
RTLD_NOW
如果指定了这个值,或者环境variables…

我不认为你select哪一个是因为你要将静态库中的所有符号链接到你的可执行文件中。

这给我们带来了下一个问题。 链接器不会在您的可执行文件中包含静态库中的符号,因为它们没有被引用 。 强制GNU链接器包含符号的方法是-Wl,--whole-archive path/to/static/lib.a -Wl,--no-whole-archive如该答案所描述的那样, -Wl,--whole-archive path/to/static/lib.a -Wl,--no-whole-archive 。 强制Mac OS X链接器包含静态库中所有符号的方法是-Wl,-force_load path/to/static/lib.a

C数组只能使用整数types进行索引。 所以写一个哈希表映射string到函数指针。

在Python,Lua和其他脚本语言中使用C程序embedded其运行时间也是值得的:C代码的一部分可以用脚本语言来操作。

Alt'ly,有些人在C中编写脚本语言扩展。然后他们可以在脚本中对C进行速度和低级访问。

你迟早会发现,使用dynamictypes的脚本语言成语(如eval())和函数名和函数名之间的模糊线以及依赖于关联数组的代码是可能的,但最终是痛苦的。

对不起,对于迟到的回复,你可以试试ngx-c-handler,它是开源的产品,它运行在fastcgi和nginx服务器上。 这对于喜欢托pipec服务器的开发者来说, https://github.com/Taymindis/ngx-c-handler 在这里输入图像描述