2010-07-07 24 views
3

我正在编写一种运行时系统/解释器,我需要做的一件事是调用位于外部的c/C++函数库。C/C++动态加载未知原型的函数

在linux上,我使用了dlfcn.h函数来打开一个库,并调用一个位于其中的函数。问题是,在使用dlsysm()时,返回的函数指针在调用之前需要转换为适当的类型,以便知道函数参数和返回类型,但是如果我在库中调用某个任意函数,显然我会在编译时不知道这个原型。

所以我问的是,有没有办法调用一个动态加载的函数,并传递它的参数,并检索它的返回值没有知道它的原型?

到目前为止,我得出的结论有没有简单的方法来做到这一点,但我已经找到了一些解决方法是:

  • 确保所有我想要加载具有相同的功能原型,并为这些函数提供一些排序机制来检索参数和返回值。这是我目前正在做的。

  • 使用内联asm将参数压入堆栈并读取返回值。如果可能的话,我真的想避免这样做!

如果有人有任何想法,那么将不胜感激。

编辑:

现在我发现正是我一直在寻找:

http://sourceware.org/libffi/

“A便携式外部函数接口库”

(虽然我承认我可以在原来的问题更清楚!)

+0

我不明白你的声明,你不知道在编译时的函数原型。 我的意思是,你打电话给dlsym()做结果?你从哪里得到“争论”呢?争论的存在意味着 - 对我来说 - 你对函数原型有一些想法。 – 2010-07-07 12:12:00

+0

如果您不知道参数或返回类型,如何调用函数? – Stephen 2010-07-07 12:14:08

+0

这些函数是在不同语言的源代码中指定的,就像Java JNI一样。所以我可以很容易地得到函数的名称来调用dlysm,但参数和类型被表示为不同的AST节点,我不能简单地将它们传递给加载的函数。 – 2010-07-07 12:28:58

回答

2

你能向外部库添加调度功能,例如一个采用某种变体类型的函数名和N(可选)参数并返回一个变体?这种调度函数原型是已知的。调度函数然后在函数名称上进行查找(或开关)并调用相应的函数。

显然如果有很多功能它就成了维护问题。

6

如果C/C++支持函数反射(即在运行时获取关于它们的类型的信息),您所要求的是什么。可悲的是,答案是否定的。

您必须使函数符合标准合约(如您所说的那样),或者开始实施机制以尝试在运行时调用函数而不知道其参数。

由于没有关于函数的知识使得它不可能调用它,我假设你的解释器/“运行时系统”至少有一些用户输入或类似的东西,它可以用来推断它试图调用一个函数,像某些东西采取了这些论点,并返回一些并不完全意外的东西即使使用反射和体面的运行时类型系统,该查找本身也很难实现。混合使用调用约定,链接样式和平台,事情很快就会变得非常糟糕。

坚持你的计划,确保您对其动态加载功能的良好定义的合同,并希望作出应有的这一点。

0

我在写一种运行时系统/解释器的过程中,和的东西,我需要能够做一个调用C/C++位于外部库中的函数。

您可以检查示例TclPython如何做。如果你熟悉Perl,你也可以检查Perl XS

一般方法是要求额外的网关库位于解释器和目标C库之间。从我使用Perl XS的经验来看,主要原因是内存管理/垃圾收集和C数据类型难以直接映射到解释器的语言。

所以我问的是,有没有办法调用一个动态加载的函数并传递它的参数,并检索它的返回值而不知道它的原型?

不知道我。

确保我要加载的所有函数具有相同的原型,并为这些函数提供一些排序机制来检索参数和返回值。这是我目前正在做的。

这是在我的项目其他团队在做什么了。他们对外部插件的类似的东西标准化的API:

typedef std::list<std::string> string_list_t; 
string_list_t func1(string_list_t stdin, string_list_t &stderr); 

常见任务的插件是执行输入变换或映射或扩展,通常使用RDBMS。

上一页接口的版本,同比增长超过时间难以维护造成的问题这两个客户,产品开发人员和第三方插件开发。由于插件相对较少被调用(而且花销比花生四周所用的SQL花费更多),所以允许轻松使用std :: string。参数stdin根据插件类型使用输入进行填充。如果内部输出参数stderr任何字符串以'E:'开头('W:'用于警告,其他静默忽略,因此可用于插件开发/调试),则认为插件调用失败。

dlsym仅在具有预定义名称的函数上使用一次,以便使用函数表(函数公共名称,类型,指针等)从共享库数组中提取数据。

+0

谢谢。你已经指出我在正确的方向:) – 2010-07-07 13:48:38

0

我的解决办法是,你可以定义一个generic proxy function,将动态功能转换为统一的原型,是这样的:

#include <string> 
#include <functional> 

using result = std::function<std::string(std::string)>; 

template <class F> 
result proxy(F func) { 
    // some type-traits technologies based on func type 
} 

在用户定义的文件,你必须添加定义做了转换:

double foo(double a) { /*...*/ } 
auto local_foo = proxy(foo); 

在你使用的系统/解释器,你可以用dlsym定义foo-function。用户定义的函数foo有责任进行计算。