在C++中动态创建函数调用

rua*_*bua 5 c c++ callstack runtime function

大家好,我希望你帮我解决这个问题:

我目前正在为脚本语言实现一个解释器.该语言需要一个C函数的本机调用接口,比如java有JNI.我的问题是,我想调用原始的C函数而不编写包装函数,它将我的脚本语言的调用堆栈转换为C调用堆栈.这意味着,我需要一种方法,在运行时生成C函数的参数列表.例:

void a(int a, int b) {
    printf("function a called %d", a + b);
}

void b(double a, int b, double c) {
    printf("function b called %f", a * b + c);
}

interpreter.registerNativeFunction("a", a);
interpreter.registerNativeFunction("b", b);
Run Code Online (Sandbox Code Playgroud)

解释器应该能够调用函数,只知道我的脚本语言的函数原型:native void a(int a, int b);native void b(double a, int b, double c);

有没有办法在C++中生成C函数调用堆栈,或者我必须使用汇编程序来完成此任务.汇编程序是一个问题,因为解释器应该几乎可以在任何平台上运行.

编辑:解决方案是使用libffi,一个库,处理许多不同平台和操作系统的调用堆栈创建.libffi也被一些着名的语言实现使用,如cpython和openjdk.

编辑:@MatsPetersson我的代码中有一个方法,我有一个方法:

void CInterpreter::CallNativeFunction(string name, vector<IValue> arguments, IReturnReference ret) {
    // Call here correct native C function.
    // this.nativeFunctions is a map which contains the function pointers.
}
Run Code Online (Sandbox Code Playgroud)

编辑:感谢您的帮助!我将继续使用libffi,并在所有必需的平台上进行测试.

n. *_* m. 5

我们可以。不需要FFI库,没有对C调用的限制,只有纯C ++ 11。

#include <iostream>
#include <list>
#include <iostream>
#include <boost/any.hpp>

template <typename T>
auto fetch_back(T& t) -> typename std::remove_reference<decltype(t.back())>::type
{
    typename std::remove_reference<decltype(t.back())>::type ret = t.back();
    t.pop_back();
    return ret;
}

template <typename X>
struct any_ref_cast
{
    X do_cast(boost::any y)
    {
        return boost::any_cast<X>(y);
    }
};

template <typename X>
struct any_ref_cast<X&>
{
    X& do_cast(boost::any y)
    {
        std::reference_wrapper<X> ref = boost::any_cast<std::reference_wrapper<X>>(y);
        return ref.get();
    }
};

template <typename X>
struct any_ref_cast<const X&>
{
    const X& do_cast(boost::any y)
    {
        std::reference_wrapper<const X> ref = boost::any_cast<std::reference_wrapper<const X>>(y);
        return ref.get();
    }
};

template <typename Ret, typename...Arg>
Ret call (Ret (*func)(Arg...), std::list<boost::any> args)
{
    if (sizeof...(Arg) != args.size())
        throw "Argument number mismatch!";

    return func(any_ref_cast<Arg>().do_cast(fetch_back(args))...);
}

int foo(int x, double y, const std::string& z, std::string& w)
{
    std::cout << "foo called : " << x << " " << y << " " << z << " " << w << std::endl;
    return 42;
}
Run Code Online (Sandbox Code Playgroud)

试驾:

int main ()
{
    std::list<boost::any> args;
    args.push_back(1);
    args.push_back(4.56);
    const std::string yyy("abc");
    std::string zzz("123");
    args.push_back(std::cref(yyy));
    args.push_back(std::ref(zzz));
    call(foo, args);
}
Run Code Online (Sandbox Code Playgroud)

读者练习:registerNativeFunction分三个简单步骤实施。

  1. 使用call接受列表的纯方法创建抽象基类boost::any,将其称为AbstractFunction
  2. 创建一个可变参数类模板,该模板继承AbstractFunction并添加指向具体类型函数(或std::function)的指针。实现call在功能方面。
  3. 创建一个map<string, AbstractFunction*>(实际使用智能指针)。

缺点:完全不能使用此方法调用可变的C样式函数(例如printf和friends)。还不支持隐式参数转换。如果将传递int给需要的函数,double它将抛出异常(这比动态解决方案可以得到的核心转储要好一些)。通过专门化,可以部分解决有限固定的一组转换问题any_ref_cast