棘手的 C 问题。动态函数调用
Posted
技术标签:
【中文标题】棘手的 C 问题。动态函数调用【英文标题】:tricky C problem. dynamic function call 【发布时间】:2011-03-26 10:02:45 【问题描述】:我正在用 C/C++ 编写一个程序(但不应涉及 c++ 类),它分为两部分。 首先是对线程和进程的基本需求。 二是供用户定制自己的功能。 模块就像,让我困惑的是用户自定义功能。
My Need is as following:
用户可以在给定的文件夹中创建一个新的 *.c 文件,他们可以编写自己的函数。
在他们制作了自己的功能和编译之后,我可能通过 socket 或 http 或 argv 命令为他们提供接口。他们可以唤起他们之前定义的功能。 他们只给我一个类似“own_funciton”的字符串,然后我调用他们定义的函数。
问题是:如何做到这一点? 我怎样才能连接字符串和函数???我认为 MACRO 可能是一个解决方案, 我要求用户像这样定义他们的功能: 这只是一个例子
BEGIN_FUNCTION (own_funcion) //函数体 END_FUNCTIONHEED:当用户添加新功能时,需要重新编译整个系统。
你可以在 MACRO BEGIN_FUNCTION 中做一些事情来存储函数字符串和函数指针.. 但是我不知道具体怎么写宏.. 你有什么建议
【问题讨论】:
您是否考虑过将 Lua 等嵌入式语言用于自定义函数? 但我的老板只允许 C 我不确定我是否理解你的解释......但我听上去很模糊,就像你想编写自己的脚本语言一样。 我同意 9000。Lua 被设计为嵌入式,占用空间非常小(什么,50k 左右?),并且在性能很重要的社区中广泛使用(例如游戏开发)。如果你有要重新发明***,您可能拥有技术上基于 C 的解决方案,但只有您自己才能理解! -1。与应用程序的功能、程序环境 (OS) 以及他们的用户类型无关。 【参考方案1】:这听起来像是一个关于如何处理动态库加载的家庭作业相关问题,这是大多数插件系统的构建方式。阅读如何在您的平台中实现动态库加载。
例如,在 linux 中,您会查看 dlopen
/dlclose
/dlsym
函数。基本上,用户实现了一个.so
对象,当您的应用程序加载它时,它会打开带有dlopen
的.so
文件,一旦加载了库,并且用户输入了一个字符串,您可以使用以下命令查找特定的函数名称dlsym
并通过函数指针调用它。完成库后,使用dlclose
发布它。
这里有一些库可以提供一些帮助,例如 Boost.Extension,它们为底层操作系统调用提供多平台接口。
【讨论】:
【参考方案2】:嗯,这对我来说听起来有点像插件架构 - 在这种情况下,这个问题可能会对你有所帮助:What's safe for a C++ plug-in system? 我想您需要编写一些通用插件,并且您的宏提供了适合用户定义函数并隐藏复杂内容的粘合剂。
您还可以查看 cppunit (http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page),它本质上使您能够编写一些函数,将它们包装在宏中,这些宏为 cppunit 框架提供粘合剂,然后让它们在通用测试运行程序中运行。但这听起来并不容易。使用像 lua 这样的脚本语言似乎更容易。
更新:有一些 c 解释器,例如 Cint (http://root.cern.ch/drupal/content/cint)。并且显然 TCC (http://bellard.org/tcc/) 支持解释器样式调用(我猜它是内联编译和执行)。我没有那样使用这些工具,但它们可能会缓解“必须将其编译成动态 dll”问题的痛苦。虽然我仍然想听听走这条路的理性,而不是使用像 Lua 这样更适合这些目的的脚本语言。
【讨论】:
我不知道 Macroideal 的合理性,但是例如 VxWorks 有一个完全支持他所描述的外壳:您可以动态加载一个库,然后从外壳调用一个函数,输入他的名字和参数.调试起来非常方便:)【参考方案3】:你有很多选择
1) 如果您的函数很小,您可以创建一个宏来简单地声明一个函数并将函数添加到指向您的类型函数的指针映射(typedef your function)
int FunctionName()
//user code
map["FunctionName"] = FunctionName;
一个不难写的宏
当你想执行时,只需从map中选择函数function并调用它
2)您的功能更大,您必须考虑使用插件系统。导出函数的 Dll。在“服务器”上,您可以枚举并加载这些 dll 并执行请求的功能
3) 一个不错的版本,其中使用允许用户在服务器上执行脚本的脚本引擎。您可以使用IActiveScript 或许多可用的免费脚本引擎之一来实现这一点。
编辑:
4) 我想到的另一种可能性。
将 .c 文件添加到 dll 项目中。 将 __declspec( dllexport ) 修饰符添加到您要添加的每个函数(最终通过宏) 这样的枚举导出函数void EnumDllFunctions() BYTE *hMod = (BYTE*)GetModuleHandle("KERNEL32.DLL"); IMAGE_NT_HEADERS *pnt = (IMAGE_NT_HEADERS*)&hMod[PIMAGE_DOS_HEADER(hMod)->e_lfanew]; IMAGE_EXPORT_DIRECTORY *exp = (IMAGE_EXPORT_DIRECTORY*)&hMod[pnt->OptionalHeader.DataDirectory->VirtualAddress]; DWORD *dwFunctions = (DWORD*)&hMod[exp->AddressOfNames]; for (DWORD ctr = 0; ctr < exp->NumberOfNames; ctr++) printf("%s\n", (char*)&hMod[dwFunctions[ctr]]);
【讨论】:
感谢您的回复,更喜欢第一个选项。但我遇到了问题。我写了一个宏,我将函数反射存储在 MACRO 中,但是 MACRO 是在函数范围之外调用的。在函数之外,C....任何其他解决方案都不允许给变量赋值。谢谢 在所有插件文件中,必须包含一个标题。该标头可以包含一个将 name-ptr 对添加到 map 的函数。【参考方案4】:听起来您正在寻找一个外部函数接口,例如libffi。
【讨论】:
以上是关于棘手的 C 问题。动态函数调用的主要内容,如果未能解决你的问题,请参考以下文章
objective-c 中如何在一个函数中调用自己类中的另外一个函数