函数,名称和参数的数组

我正在尝试使用输入(来自文件)的函数 – 按名称命名。

例如 – 在我写的文件中

functionOne(1,2) 

我成功地将函数名称和他的参数分离到不同的数组 – 现在我有:

  funcName[] = functioOne funcArg[0] = 1 funcArg[1] = 2 

但是,现在我卡住了 – 我怎么能用它? 我试图创建一个指向函数的指针数组,但不知道如何使用它。 有什么建议吗? 谢谢

C没有内省 。 在运行时期间,不可能从字符串中获取或调用函数。

但是有一些解决方法。 例如,您可以创建一个包含函数名称和指向函数的指针的表。 然后,您可以搜索此表以查找要调用的函数。

也许是这样的

 void functionOne(int arg1, int arg2) { ... } struct { char *name; void (*function)(int, int); } functions[] = { { "funcitonOne", &functionOne }, }; 

为了使它更通用,当你有许多函数使用不同数量的参数时,它会更难一点。 然后你可以不像正常那样传递参数,而是传递一个包含参数的数组:

 void functionOne(int *arguments) { // arguments[0] is the first arguments, etc. ... } 

相应地修改结构中的函数指针。

如果参数类型也不同,那么您可以使用带有type-tag和union的结构作为值。

你无法在C中做你想做的事情。你最接近的是,保留一个函数指针数组,它们将指向各自的function。 还要保留一个字符串数组,这与其他数组的索引完全相同。 现在,无论何时获得函数名称 – 只需解析它,比较并根据匹配字符串的索引获取相应的函数指针。

如何发送arguemnts – 很好地做到这一点我会说你去做 – 当你知道你将要调用哪个函数时,你解析文件本身的参数(你会知道这个函数需要2个arguemnts – 所以你将获得该行并将其解析为int并按预期double ,然后你将相应地调用它。

一般情况下, 你不能在便携式 C11 (读取n1570 )中做你想要的 ,正如其他人所解释的那样: 函数名称是编译时的东西 ,在执行时是未知的。 C编程语言没有reflection和/或内省 。 顺便说一句,一个函数甚至可能在优化编译期间“消失”(所以在运行时“实际上”并不存在,但是你的程序就像是存在这个函数一样),从某种意义上说它已经被内联或从可执行文件中删除了。 但是,C有函数指针 (其类型描述了间接调用函数的签名); 实际上,他们指的是机器代码 。


但是如果你在运行Linux的x86-64计算机上编写应用程序代码,你有时会遇到一些变通方法,使用一些特定于该操作系统和指令集架构的 “脏”技巧:

  • 给定一些类似"functionOne" 字符串 (实际上,类型为const char* ),你可以获得一个指向它的函数指针(例如functionOne ,只要它有extern 链接 ) – 通过动态链接工具 – 使用dlopen(3)和NULL路径,然后是dlsym(3) 。 通过dladdr(3)可以获得反向映射(从地址到名称) 。

  • 给定一个函数指针 (或实际上虚拟地址空间中指向某个可执行 代码段的任何有效地址),如果在编译时已知该函数的签名,则可以间接调用它(它以该函数指针的类型给出) )。

  • 如果要调用具有任意签名和任意参数的任意函数(仅在运行时已知),则可以使用libffi 。 它知道你的系统的ABI 。

  • 一个可能的技巧是发出一些包含C代码的临时文件/tmp/emittedcode.c (在运行时),将编译过程分成一个临时插件(例如gcc -Wall -O -shared -fPIC/tmp/emittedcode.c -o /tmp/emittedplugin.so ),并使用dlopen(3) 动态加载临时插件/tmp/emittedplugin.so 。 务必在程序终止时清除混乱(例如,删除所有临时文件,可能使用atexit(3) )。

  • 也许你想在运行时生成一些机器代码; 然后还考虑一些JIT编译库,如GCCJIT , LLVM , libjit , asmjit 。

如果您的PC没有运行Linux,您可能会找到适合您的操作系统和计算机的东西。 阅读操作系统:三个简单的部分,以了解有关操作系统的更多信息。 阅读特定操作系统的文档(对于Linux,首先阅读ALP或一些有关Linux编程的新书,然后是介绍(2) , 系统调用(2) , 精灵(5)和相关页面)。


顺便说一句,如果你只是想从程序中调用函数(来自某个输入文件中的名称),你可能会在初始化时构建一些将函数名与函数指针相关联的哈希表 (或映射 ,也许是红黑树 ),如建议的那样在另一个答案中。

也许你想要一些具有一些eval原语的 homoiconic编程语言。 看看Common Lisp。 注意SBCL ,它在大多数REPL交互中编译成动态生成的机器代码。

也许你正在写一些翻译 (这通常比你想象的更困难和耗时,阅读龙书 )。 考虑嵌入和使用现有的,例如Guile或Lua 。